Never-ending Pumpkin Mulch

    svelte-integration-red

    1.4.3 • Public • Published

    Svelte-Integration-RED (SIR)

    SIR integrates Svelte into Node-RED and allows to write the editor-part of your node using Svelte templates.

    Svelte itself is only needed during development. Anyone using your node will use the generated HTML file. This file may be a bit bigger than a hand-written version. Anyway, the development of node editors gets way easier and neat. Especially if your editor is quite complex or has dynamic parts. And furthermore you can easily write editor components and reuse them.

    Install

    Install SIR global with

    npm install -g svelte-integration-red

    Then you can run the build-process with the command sir in your project's main directory. SIR will analyze your package.json and check if it finds a .svelte template and a .doc.html for any node mentioned within. It then compiles these to HTML files that comply with Node-RED's HTML file format. If your node is not in the same directory than your package.json you can also submit the path to it's folder as a command line parameter (like the test-node example below).

    Usage

    Create your first node

    Creating a Node-RED node with SIR is mostly similiar to a normal Node-RED node.

    Register your node in the package.json

    {
      "name": "my-node",
      "version": "0.0.1",
      "description": "My awesome node",
      "node-red": {
        "nodes": {
          "my-node-name": "my-node-name.js",
        }
      }
    }
    

    Create a .js file with the following code:

    module.exports = function (RED) {
      function MyNodeName (config) {
        RED.nodes.createNode(this, config)
        const node = this
        node.name = config.name
      }
      RED.nodes.registerType('my-node-name', MyNodeName)
    }
    

    And instead of the .html file, which will be created later by SIR you need a .svelte file.

    Attention: The Node-RED part must be stated in <script context="module"> and you must state the three functions render, update, revert. If you want to set your node to a minimum width, you can add that in the render option object => e.g. render(this, { minWidth: "600px" }).

    <script context="module">
      /* This is mostly identical to a standard Node-RED node. Important: It must be stated in script context="module"! */
      RED.nodes.registerType("my-node-name", {
        category: "common",
        defaults: {
          name: { value: "", label: "Name", placeholder: "Enter a name for this node" },
          nodeVersion: { value: ""}
        },
        inputs: 0,
        outputs: 1,
        color: "#CEC0DE",
        icon: "font-awesome/fa-tag",
        label: function() {
          if (this.name) return this.name;
          return "No name set";
        },
        oneditprepare: function () {
          render(this)
        },
        oneditsave: function () { 
          update(this)
        }, 
        oneditcancel: function () {
          revert(this)
        },
        onadd: function () { 
          addCurrentNodeVersion(this) 
        }
      });
    </script>
    
    <script>
      // get your node variable from extern and import the needed components from SIR
      export let node
      import { Input, Button } from 'svelte-integration-red/components'
      // then add your javascript functions
      const myButtonFunc = () => alert('The button was pressed')
    </script>
    
    <!-- Now enter your svelte code -->
    <!-- just bind node and set the property name which you have stated above in the defaults variable -->
    <Input bind:node prop="name" />
    <Button icon="plus" label="Click me" on:click={myButtonFunc}/>
    

    This will be the result:

    Screenshot of a sample-node.

    Create your node documentation

    Documentation and your node code are separated. Just create a my-node-name.doc.html for a html or a my-node-name.doc.md for a markdown documentation file and SIR will merge it later. Further examples can be found here.

    <p>This is a documentation for my node in html.</p>
    
    <h3>Inputs</h3>
      <dl class="message-properties">
          <dt>payload
              <span class="property-type">string | buffer</span>
          </dt>
          <dd> the payload of the message to publish. </dd>
          <dt class="optional">topic
              <span class="property-type">string</span>
          </dt>
          <dd> the MQTT topic to publish to.</dd>
      </dl>
    
    <h3>Details</h3>
        <p>Documentation is very important!</p>
    
    This is a markdown documentation.
    
    ### Inputs
    
    : payload (string | buffer) :  the payload of the message to publish.
    : *topic* (string)          :  the MQTT topic to publish to.
    
    
    ### Details
    Documentation is very important!
    

    Components

    With SIR you can easily use the following components to create your awesome Node-RED Node.

    You can also find more and complexer examples in the test-node.svelte file. There are also detailed comments for each component: source code.

    Button

    This component creates buttons. Just set the needed properties:

    • clazz: Add a class to this component.
    • disabled (boolean): Disable the button.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • icon: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • id: Set a custom id for your Button. If no id is stated SIR will create an uuid.
    • indented (boolean): Shift your button to the same position as it would have a label. (See example picture)
    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)
    • label: Set a name to show what that button will do.
    • maximize (boolean): Set the button to highest available width within your Row.
    • node: Bind your node property to get access to most features.
    • primary (boolean): Set the primary color of your theme (e.g. standard Node-Red would be a red button).
    • small (boolean): Will reduce the size of the button.

    Events:

    • on:click (function): Triggers a function stated in <script> or directly like the example below.
    <Button small icon='edit' on:click={() => alert('You clicked edit.')} />
    

    Button example

    Callout

    Callouts are info boxes which will highlight important information.

    <Callout type="info">
      <span slot="header">I am a callout infobox</span>
      You can use <b>html</b> <u>styling</u> and fill me with useful tips!'
    </Callout>
    

    Callout example

    Callout properties:

    • closeable (boolean): Adds a close button.
    • clazz: Add a class to this component.
    • icon: Set a custom icon for your callout box.
    • indented (boolean): Shift the callout to the right (like it would have a label).
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • small (boolean): Creates a small callout box.
    • show (boolean): Show / Hide the callout.
    • type: Set the type for different styling: info, warning, error, success.

    Collapsible

    The Collapsible component is great if you want to hide content that is seldomly needed or in case you want to define a kind of tree editor. For the latter case you should set the indented flag.

    <Collapsible collapsed label="Click me">
      <Input maximize value="Some content."/>
      <Collapsible indented label="More content with extra long label">
        <Input maximize value="More content. :)" />
        <Input maximize value="And even more! :o" />
      </Collapsible>
    </Collapsible>
    

    Collapsible example

    • border (boolean): Set a border around your collapsible box.
    • clazz: Add a class to this component.
    • collapsed (boolean): Show or hide the content when opening the node.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • indented (boolean): Shift the component a bit to the right. Useful if stated within another component (example below)
    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)
    • label: Set the name for your label, which will show/hide the content if clicked.
    • maximize (boolean): Set the collapsible to full width.
    • node: If your label has a translation you must set the node property or set the path via i18n.

    ConfigNode

    The config node is a special <Input> component. Just set in the defaults in type the name of your config node and in the Input component the type "config". How to create custom nodes can be found here:.

    The following properties are valid and are identical to the normal <Input> component: node, prop, icon, label, id, disabled, maximize, i18n.

    defaults: {
       broker: { type: 'mqtt-broker', label: 'Broker' }, // mqtt-broker is a standard Node-RED config node
    }
    
    <Input type='config' {node} prop="broker"/>
    

    Input config example

    EditableList

    The editable list component helps you to visualize and to edit array variables. Unlike most components we use 'default' only to save the value of the array. Note: This component won't use jQuery since version 1.0.4 which leads to a different sorting animation as the standard Node-Red EditableList.

    defaults: {
      values: { value: ["Hello", "world", "here", "I", "am."] },
    }
    
    <EditableList {node} label="Values" icon="list" bind:elements={node.values} let:element={value} let:index sortable removable addButton >
        <Input inline maximize {value} on:change={(e) => node.values[index] = e.detail.value} placeholder="Value name" disabled={node.disableInput}></Input>
    </EditableList>
    

    Editable list example

    You can state the following properties:

    Properties

    • addButton (boolean or string): Set an add button to create a new value. If set as string you can change the button label.
    • clazz: Add a class to this component.
    • disabled (boolean): Disable editing.
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon: Set an icon for your label.
    • indented (boolean): Shift your list a bit to the right. Useful if stated within another component.
    • elements: Bind your array variable. Then create a element and index variable to work with (see description below).
    • fading (boolean | number): Fades the component when hiding or showing (not on opening). ndex.
    • height (number | string): Set a fix height to your list. Default is auto.
    • label: Set a headline for your list.
    • maxHeight (number | string): Set a maximum height to your list. Default is 300px.
    • maximize (boolean): Set the list to full width.
    • minHeight (number | string): Set a minimum height to your list. Default is 100px.
    • node: If your label has a translation you must set the node property or set the path via i18n.
    • removable (boolean): Allows to delete the value.
    • sortable (boolean): Allows to change the value i

    Events

    • on:add (function): Set a function that will be triggered when adding new values.
    • on:remove (function): Set a function that will be triggered when removing values.
    • on:sort (function): Set a function that will be triggered when sorting values.

    Slots

    • header: Set a header above the editable list.
    • headerTable: Set a table header.

    Attention: The bound elements are automatically iterated using their index as id. This may lead to unexpected behaviour when removing elements from the list. To prevent this, your elements may define an id property that is used as an alternative to the index.

    To render an element, assign the element to a variable (here: value). You can then render them in any way you like within the EditableList's HTML content. Keep in mind that you may not bind to the node from within here as your elements are not direct children of your node. Use the value property and the change event instead.

    Group

    Groups allow to render a border around other components.

    <Group label="Just grouped content" icon="minus">
      <Input maximize label="First" value="First input" disabled={node.disableInput}/>
      <Input maximize label = "Second" value="Second input" disabled={node.disableInput}/>
    </Group>
    

    Group example

    Group properties:

    • clazz: Add a class to this component.
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon: Set the icon for your label.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • label: Set the name for your headline.
    • maximize (boolean): Set the group to full width.
    • node: If your label has a translation you must set the node property or set the path via i18n.

    Input

    Creates a Input field. If you want to refer to one of your 'default' properties like name in this example

    RED.nodes.registerType("my-node-name", {
      category: "common",
      defaults: {
        name: { value: "", label: "Name" }
      },...
    

    you can create your Input field simply with:

      <Input bind:node prop="name"/>}
    

    Input example

    Input has the following properties. Properties markes with '*' can be stated in 'default':

    • checked (boolean): Only available for checkboxes. Will be intern handled like the value property.
    • clazz: Add a class to this component.
    • credentials: If your input is a credential set this to true.
    • disabled (boolean): Deactivate the input field.
    • error (boolean): Bind a variable which will mark the input field as invald. Warning: This is only visible on the UI and for not node bound input fields.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon*: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • id: Set a custom id for your input field. The id will always have the prefix 'node-input-'. If no id is stated it will take the key name or create an uuid.
    • indented (boolean): Only neccessary if you don't have a label. Will shift your input field to the same position as it would have a label.
    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)
    • label*: Enter your label name, if empty it will state the key name. Set to false if you don't want a label.
    • maximize (boolean): Set your input field to the highest available width within your Row.
    • node: Bind your node property to get access to most features.
    • placeholder*: Enter a placeholder text if no value is stated.
    • prop: The key name of your property within 'default'.
    • type*: Enter one of these types to create a specific input field: text, number, password, email, url, checkbox, color
    • value*: Set the value of the input field. If you use a custom variable it must be bound (bind:value=myVariable). This variable must be created within the svelte <script> tag.

    MenuEntry

    Creates a Menu Entry. Together with Popover you can create a context menu like element (which have to be open with the left mouse button).

      <MenuEntry on:click={ () => alert('you clicked entry 1') }>Entry 1</MenuEntry>
      <MenuEntry on:click={ () => alert('you clicked entry 2') }>Entry 2</MenuEntry>
      <MenuEntry expandable title="Header 1">
        <MenuEntry on:click={ () => alert('you clicked entry 3') }>Entry 3</MenuEntry>
        <MenuEntry on:click={ () => alert('you clicked entry 4') }>Entry 4</MenuEntry>
      </MenuEntry>    
    

    MenuEntry Example

    Popover properties:

    • clazz: Add a class to this component.
    • expandable (boolean): Set to create a new Menu child component (Header 1 in the picture). Default: false.
    • id: Set a custom id for your component. If no id is stated SIR will create a uuid.
    • maxHeight: Set a maximal height for your component. Default is window.height.
    • title: Only if expandable -> Set a title for your header.

    Panel

    A Panel is a Component with 2 boxes which are resizable. Just enter your content in either the top or bottom slot.

    <Panel label="Resizable Panel" height="300" topHeight="180" border>
      <div slot="top" style="padding: 5px;">
        <Input label="Top input" placeholder="I am the top input"/>
        <Callout type="info">
          Hello world!
        </Callout>
      </div>
      <div slot="bottom" style="padding: 5px;">
        <Input label="Bottom input" placeholder="I am the bottom input"/>
        <Callout type="warning">
          Goodbye world!
        </Callout>
      </div>   
    </Panel>
    

    Panel Example

    Panel properties:

    • border (boolean): Set a border around your collapsible box. Default (false)
    • clazz: Add a class to this component.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • height (Number) Sets the height of the panel. Default "500".
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon: Set an icon next to the label.
    • id: Set a custom id for your component. If no id is stated SIR will create a uuid.
    • label: Enter a name which will be shown above the panel.
    • node: Bind your node property to get access to most features.
    • topHeight (text | number): Define the default height of the top panel. Default: "70%".

    Experimental: Popover

    Creates a popup element at it's button position. If used with modal, it will close if clicked outside the popover element.

    <Popover label={showPopover ? "Close Menu" : "Open Menu"} bind:showPopover={showPopover}>
      <Input inline placeholder="I am a dummy input field"/>
      <Button inline on:click={() => showPopover = false} label="Close Popover Menu"/>
    </Popover>
    

    Popover Example

    Popover properties:

    • button (boolean): Create a button to open the popover. Default: true.
    • clazz: Add a class to this component.
    • disabled (boolean): Disable the popover Button. Default: false.
    • icon: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • id: Set a custom id for your component. If no id is stated SIR will create a uuid.
    • label: Label for the Button.
    • modal (boolean): Creates a modal background. If clicked outside the popover, the popover will close. Default: true.
    • showPopover (boolean): Show / Hide the popover. Default: false.
    • small (boolean): Create a small button. Default: false.

    Popup

    Create easy but complex Node-RED popups. You just need something to trigger the popup, like a button. If the popup is fixed you must import the closePopup function to close the popup again :).

    Simple warning/error popups are also possible, but those are propably more easy to create with the RED.notify()

    <script>
      import { closePopup } from '../components/Popup.svelte' // <-- neccessary import to close popups if fixed
    
    let showRiddlePopup = false
    let keysPopup = {
      enter: () => {
        if (node.insidePopup === 'friend') {
          closePopup("riddlePopup")
        } else {
          alert('think again Gandalf!')
        } 
      },
      escape: () => {
        alert('You pressed escape. The popup will close now')
        closePopup("riddlePopup")
      },
      a: () => {
        alert('There is no a in friend!')
      }
    }
    </script>
    
    <Button label='Show riddle popup' on:click={ () => showRiddlePopup = true }></Button>
    
    <Popup id="riddlePopup" modal fixed bind:showPopup={showRiddlePopup} focus="insidePopup" keyboard={keysPopup}>
      <h2>Speak "friend" and enter!</h2>
      <Input bind:node type='text' prop='insidePopup'></Input>
      <span slot="buttons">
        <Button label='Okay' primary disabled={node.insidePopup !== 'friend'} on:click={() => closePopup("riddlePopup")} />
        <Button label='Cancel' on:click={cancelPopup} />
        <Button label='Give me a hint' on:click={ () => alert("It's literal 'friend' Gandalf! And don't speak it out, but type it in the field...") } />
      </span>
    </Popup>
    

    Popup example

    Popup properties:

    • fixed (boolean): If set, the popup will stay till closed by closePopup
    • focus: If you have an input field you can focus on it by stating the input field id.
    • id: If you want to close the popup by a function, set a unique id which you can later use with closePopup(id).
    • keyboard: Object where the key is the keyboard key and the value is a function
    • modal (boolean): Prevents changing something in Node-RED while the popup shows.
    • showPopup: Bound variable to trigger the popup.
    • timeout (number): If not fixed you can set a timeout to close the popup (default: 5000 ms)
    • type: Sets the styling of the popup: 'info', 'warning', 'error'

    Row

    This is just a simple row. Usually components use this component automatically to keep the same distance.

    If you want to combine input elements within one row you must state the row component and set the input elements inside. Within your Row some elements like the input field must set to 'inline'.

    <Row>
      <Input type='text' inline maximize {node} prop="myVariable" />   
      <Button icon="trash" on:click={() => alert('You clicked on the trash can button')} />
      <Button icon="plus" on:click={() => alert('You clicked on the plus button')} />
      <Button icon="close" on:click={() => alert('You clicked on the close button')} />
    </Row>
    

    Row example

    Row has the following properties:

    • clazz: If you want to state a css class (setting class property is prohibited by svelte).
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • id: Set a custom id for your component. If no id is stated SIR will create an uuid.
    • inline: Set the row to inline instead of flex.
    • indented (boolean): Shift your components to the right. Useful if stated within another component. Default: false.
    • maximize: Set the row to full width.

    Allowed events: click, dblclick, mouseenter, mouseleave

    Select

    Select let the user choose from a dropdown list. The options can also be created by svelte #each.

    defaults: {
      selectionTwo: { value: "hello", label: "Selection two" }
    }
    
    <Select bind:node prop="selectionTwo">
      <option value="hello">Hello</option>
      <option value="world">World</option>
    </Select>
    

    Select example

    Select has the following properties. Properties markes with '*' can be stated in 'default':

    • clazz: Add a class to this component.
    • disabled (boolean): Disable selecting.
    • error (boolean): Bind a variable which will mark the input field as invald. Warning: This is only visible on the UI and for not node bound input fields.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • id: Set a custom id for your Select component. If no id is stated SIR will create from the default key name or an uuid.
    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)
    • label*: Enter your label name, if empty it will state the key name. Set to false if you don't want a label.
    • maximize (boolean): Set the disable component to full width.
    • node: Bind your node property to get access to most features.
    • prop: The key name of your property within 'default'.
    • value*: Set the value of the input field. If you use a custom variable it must be bound (bind:value=myVariable). This variable must be created within the svelte <script> tag.

    TabbedPane + TabContent

    With the help of those two components you can create tabs for your node. TabbedPane is the outer box of your Tabs. TabContent will hold the components that will be shown, if the tab is active.

    Define Tabs by using an object where the key is the tabs name. The tab object key is the identifing name for the TabContent, the value can either be a string (label) or an object to show a label and an icon.

    <script>
    let tabs = { "props": "Properties", "buttons": { name: "Buttons", icon: "truck" }, "list": "List", "groups": "Groups", "callouts": "Callouts", "popups": "Popups", "table": "Table" }
    </script>
    
    <TabbedPane bind:tabs>
    	<TabContent tab="props">
      ... <-- here is your content that will be shown if the tab is active
      </TabContent>
      
      <TabContent tab="buttons">
      ...
      </TabContent>
      ...
    </TabbedPane>
    

    Tabs example

    TabbedPane properties:

    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • node: If your label has a translation you must set the node property or set the path via i18n.
    • tabs: An object with the key as the name for the tab and the value as the label (string) or an object with name and icon.

    Table

    Create a table which can also edit its values.

    defaults: {
      myTable: { 
        value: {
          header: ['col1', 'col2', 'col3', 'col4'],
          rows: [
            ['hello', 'world', 'this is', 'my first row'], 
            ['hello', 'world', 'this is', 'my second row'], 
            ['hello', 'world', 'this is', 'my third row'], 
            ['hello', 'world', 'this is', 'my fourth row']
          ]
        }
      },
    }
    
    <Table bind:node prop='myTable' editable={true} on:afterAddRow={(event) => console.log(event.detail)/>
    

    Table example

    Table properties:

    • clazz: Add a class to this component.
    • editable (boolean): Allows editing of the table. Default: false.
    • editColumns (boolean): Allows editing of the columns/header. Default: true.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • header: Can be used instead of the header from the value object.
    • i18n: This property can be used to either deactivate translation of the header (set to false) or to set the path to a specific translation file.
    • id: Set a custom id for your component. If no id is stated SIR will create from the default key name or an uuid.
    • node: Bind your node property to get access to most features.
    • prop: The key name of your property within 'default'.
    • rows: Can be used instead of the rows from the value object.
    • value: Set the value for the table. Must be an Object with header: [] and rows: [].

    Table has the following events:

    • beforeEditTable
    • afterEditTable
    • afterCancelEditTable
    • afterEditColumns
    • afterEditRow
    • beforeAddRow
    • afterAddRow
    • afterAddColumn
    • afterDelete

    MultilineText / Textarea

    Creates a multiline input field.

    defaults:  {
      textarea: {value: 'This is a multiline input field', label: 'Textarea', placeholder: 'Please enter something'},
    }
    
    <Textarea bind:node prop='textarea' />
    
    

    Textarea example

    Textarea has the following properties. Properties markes with '*' can be stated in 'default':

    • clazz: Add a class to this component.
    • cols (number): Default html textara property. Changes the width.
    • disabled (boolean): Disables the input.
    • error (boolean): Bind a variable which will mark the input field as invald. Warning: This is only visible on the UI and for not node bound input fields.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon*: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • id: Set a custom id for your input field. The id will always have the prefix 'node-input-'. If no id is stated it will take the key name or create an uuid.
    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)
    • label*: Enter your label name, if empty it will state the key name. Set to false if you don't want a label.
    • maximize (boolean): Set the textarea component to full width.
    • maxlength (number): Limits the amount of entering symbols.
    • node: Bind your node property to get access to most features.
    • placeholder*: Enter a placeholder text if no value is stated.
    • prop: The key name of your property within 'default'.
    • rows (number): Default html textara property. Changes the height. Default value: 5.
    • value*: Set the value of the input field. If you use a custom variable it must be bound (bind:value=myVariable). This variable must be created within the svelte <script> tag.

    ToggleGroup

    With ToggleGroup you can select one or multiple related options. You can choose between buttons (standard), checkbox or radio input fields. With radio input can only choose one option!

    Important: If multiple options are possible the result will always be stated in an array.

    defaults: {
      toggleSingle: { value: 'left', label:"Select one", icon:"check"},
      toggleMulti: { value: ['you', 'more', 'one'], label:"Select multiple", icon:"list-ol"},
    }
    
    <script>
      const groupedInputOptions = [
        { icon: 'align-left', label: 'label.left', value: 'left' },
        { icon: 'align-center', label: 'label.center', value: 'center' },
        { icon: 'align-right', label: 'label.right', value: 'right' },
        { icon: 'align-justify', label: 'label.justify', value: 'justify' }
      ]
      const groupedInputOptionsMulti = [ 'you', 'can', 'select', 'more', 'than', 'one']
    </script>
    
    <ToggleGroup bind:node prop="toggleSingle" options={groupedInputOptions}/>
    <ToggleGroup bind:node prop="toggleMulti" options={groupedInputOptionsMulti} gap={false} multiselect={true} />
    

    ToggleGroup example

    ToggleGroup has the following properties. Properties markes with '*' can be stated in 'default':

    • clazz: Add a class to this component.
    • disabled (boolean): Disable selecting.
    • fading (boolean | number): Fades the component when hiding or showing (not on opening).
    • gap (boolean): Only for button type. Creates a gap between the selecting values. Default: true
    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.
    • icon*: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • id: Set a custom id for your component. If no id is stated SIR will create from the default key name or an uuid.
    • indented (boolean): Only neccessary if you don't have a label. Will shift your input field to the same position as it would have a label.
    • inline (boolean): Set the option in one row or set one row for each option. Radio button is always false. Default: true
    • label*: Enter your label name, if empty it will state the key name. Set to false if you don't want a label.
    • multiselect (boolean): Select more than one option.
    • node: Bind your node property to get access to most features.
    • options: Set an Array with possible selecting options. Each value can either be a string or an object with the keys: icon, label, value.
    • prop: The key name of your property within 'default'.
    • type: Select the styling: button (default), checkbox or radio (only for single selection)
    • value*: Set the value for the group. If you use a custom variable it must be bound (bind:value=myVariable). This variable must be created within the svelte <script> tag.

    TreeNode

    A tree node is a hoverable and selectable component which is often used to show a hierarchical or repitite structure. A tree node can be the root element, a branch or the leaf. Bind selected and hovered to a variable. The hovering and selection of the row works for the tree headers automatically. As the structure of the tree childs is unknown you must set the id of the child row to the selected / hovered variable. Most of the times this can be done by get the closest ".sir-Row".

    <script>
      const myTree = [
        { label: "tree 1", icon: "search"},
        { label: "tree 2", icon: "truck"},
        { label: "tree 3", icon: "bullhorn"},
        { label: "tree 4", icon: "camera"}
      ]
    
      let treeSelect
      let treeHover
      const getRow = (e) => e.target?.closest(".sir-Row")?.id
    </script>
    
    <style>
      .myRow { padding: 2px 0; }
      .myButton { margin-right: 6px; }
    </style>
    
    {#each myTree as { label, icon }, i}
      <TreeNode {label} bind:selected={treeSelect} bind:hovered={treeHover}>
        <Row clazz="myRow" maximize on:mouseenter={(e) => treeHover = getRow(e)} on:click={(e) => treeSelect = getRow(e)} >
          <Button {icon} small inline clazz="myButton" on:click={(e) => treeSelect = getRow(e)} />
          Welcome to {label}
        </Row>
        <TreeNode label="{label} subtree" bind:selected={treeSelect} bind:hovered={treeHover}>
          <Input label="{label} input" />
        </TreeNode>
      </TreeNode>
    {/each}
    

    TreeNode example

    ToggleGroup has the following properties. Properties markes with '*' can be stated in 'default':

    • clazz: Add a class to this component.
    • collapsible: Is the TreeNode a collapsible or a simple row (default = true)
    • collapsed (boolean): Show or hide the content when opening the node. Default = false
    • hoverable (boolean): Makes the tree hoverable. Default: true
    • hovered: Bind a variable in which the id of the hovered component is saved.
    • id: Set a custom id for your component. If no id is stated SIR will create from the default key name or an uuid.
    • icon: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".
    • indented (number): Set the indented width. Default: 12 (px)
    • label: Set the name for your label, which will show/hide the content if clicked and is a collapsible.
    • recreateTreeDepth: Trigger to recreate the tree depth. Useful if elements are dynamically added.
    • selectable (boolean): Makes the tree selectable. Default: true
    • selected: Bind a variable in which the id of the selected component is saved.

    TypedInput

    TypedInputs are Node-RED specific fields which combine a selection field and an input field.

    defaults: {
      content: { value: '', label: 'Content',  validate: RED.validators.typedInput("contentType") },
      contentType: { value: 'str', types: ["str", "bool", "num"] },
    }
    
    <TypedInput {node} prop="content" typeProp="contentType" bind:types={contentTypes} disabled={node.disableInput}/>
    

    TypedInput example

    TypedInput has the following properties. Properties markes with '*' can be stated in 'default':

    • clazz: Add a class to this component.

    • disabled (boolean): Deactivate the in

    • i18n: This property can be used to either deactivate translation (set to false) or to set the path to a specific translation file.

    • icon*: Set a Font-Awesome icon for your label. Just enter the icon name, without "fa fa-".

    • label*: Enter your label name, if empty it will state the key name. Set to false if you don't want a label.

    • fading (boolean | number): Fades the component when hiding or showing (not on opening).

    • id: Set a custom id for your input field. The id will always have the prefix 'node-input-'. If no id is stated it will take the key name or create an uuid.

    • inline (boolean): Use this option if you want to put multiple items in one row. (Disables sir-Row class)

    • indented (boolean): Will shift your input field to the same position as it would have a label. put field.

    • maximize (boolean): Set your input field to the highest available width within your Row.

    • node: Bind your node property to get access to most features.

    • prop: The key name of your property within 'default'.

    • typeProp: Set the value of the (left) selection field.

    • type: Instead of typeProp: bind the value of the (left) selection field.

    • types: Instead of typeProp: bind the selectable values of the (left) selection field.

    • value*: Set the value of the (right) input field. If you use a custom variable it must be bound (bind:value=myVariable). This variable must be created within the svelte <script> tag.

    Update your Node

    You can use SIR to automatically update your nodes if critical changes were made. This is useful if you changed a variable name, the type of a variable or the variable needs a (new) default value. Just follow these steps:

    • You have to add "nodeVersion" to your node default with an empty string value. (Check example at the beginning)
    • Add the method "onadd" to your node. (Check example at the beginning)
    • Create a "my-node-name-update.js" file with the following code. This function will be started automatically after Node-RED is ready.
      const clientUpdate = (version, node) => {
        // v = {major: 0, minor: 1, patch: 1, tag: 'beta-1', string: '0.1.1-beta-1'}
        const { major, minor, patch } = version
        if (major <= 1) {
          // v.1.x.x
          if (minor <= 1) {
            // v.1.1.x
            if (patch < 1) {
              // v.1.1.1
              node.name = 'Enter a name'
            }
            if (patch < 2) {
              // v.1.1.2
              node.name = 'Enter a really good name'
            }
          }
        }
        return node
      }
      
      module.exports = { clientUpdate }
      
      • Server side updating will be added... But theoretically you can add a serverUpdate function in the update.js and import it. You just have to check the version for yourself...
      // my-node-name-update.js
      const serverUpdate = (config) => {
        // TODO find a good way to put the version parse automatically here...
        // const currentVersion = config.NodeVersion
        return config
      }
      
      // my-node-name.js
      config = require('./test-node-update').serverUpdate(config)
      

    Trying SIR with Gitpod

    If you want to test SIR you may run this project within Gitpod which is integrated into GitLab and just a click away. After your workspace is up and running, you need to run the following commands in order to compile the test-node's svelte template and run node-red:

    gitpod /workspace/svelte-integration-red $ sir test-node
    Found svelte-file test-node/test-node.svelte for node test-node.
    Created HTML version of test-node/test-node.svelte
    gitpod /workspace/svelte-integration-red $ node-red

    You will see a message that a new port has been opened. Just click on "Open Browser" and Node-RED will open in a new browser tab where you can try the test node's behaviour. Feel free to change the template, recompile it and re-run Node-RED to get a feeling for SIR.

    License

    This repository and the code inside it is licensed under the MIT License. Read LICENSE for more information.

    Not yet implemented

    The following components / features have will be implemented

    • [ ] Add event forwarding for all events (waiting for svelte to implement...)

    Install

    npm i svelte-integration-red

    DownloadsWeekly Downloads

    96

    Version

    1.4.3

    License

    MIT

    Unpacked Size

    399 kB

    Total Files

    67

    Last publish

    Collaborators

    • 2weltenchris
    • meijey