svelte-integration-red

2.0.1 • 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).

Compile single files with sir myNodeName.svelte

The html file will automatically be minified. If you need a more readable version for debugging purposes use sir -m=false.

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" },
      _version: { 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.
  • tooltip: Shows a tooltip when hovering the button.
  • tooltipOptions: See details under Tooltip component.

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

Button Group

This component creates a button group similar to a toggle group. Main difference is that we place the button directly inside the button group and have therefor full control over the styling. A button is also not selected after clicking.

<ButtonGroup label="A button group">
  <Button inline icon="truck" label="We are also indented" />
  <Button inline icon="globe" label="I am number 2" />
  <Button inline icon="trash" label="I am the third button" />
</ButtonGroup>

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.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.

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:.

If you are editing a node which is using the config node input and you want to react directly after changing the config node, you can use the Node-RED filter function. Please note that SIR uses two properties to enable changing the active node values (see example below).

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

defaults: {
  // mqtt-broker is a standard Node-RED config node
  broker: { type: 'mqtt-broker', label: 'Broker', filter: function (configNode, node) {
    // a function to react after changing the config node in your node
    console.log(configNode, 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

Editable list 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.
  • filter (function): Filter elements from your list. If returns true it will be shown.
  • 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
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.

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.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.

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'.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.
  • type*: Enter one of these types to create a specific input field: text, number, password, email, url, checkbox, color or search for a simple Node-RED like search field
  • 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.

Credentials Input

Prepare your credenctials like in the credentials readme.

Use instead of the Node-RED html input this code.

  <Input bind:node prop="username" credentials />
  <Input bind:node prop="password" credentials type="password" />

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

MenuEntry properties:

  • clazz: Add a class to this component.
  • closeOtherPopovers: Opening an popover closes other popovers.
  • 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()

Translations within a Popup should be made with the RED._() function instead of data-i18n!

<script>
import Popup, { closePopup } from 'svelte-integration-red/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>
  <!-- use RED._(...) instead of <span data-i18n="..." /> for translating texts -->
  <span>{RED._('my-node/my-node:popup.text')}</span>
  <Input bind:node type='text' prop='insidePopup'></Input>
  <!-- use svelte:fragment to remove unneccessary slot DOM -->
  <svelte:fragment 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...") } />
  </svelte:fragment>
</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 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.

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 properties (Properties 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'.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.
  • 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 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.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.

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 properties (Properties 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'.
  • tooltip: Shows a tooltip on label / label icon.
  • tooltipOptions: See details under Tooltip component.
  • 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.

Tooltip

Add a tooltip to a custom component. Most Sir-Components have this component included and only needs the property "tooltip" and optional "tooltipOptions".

Tooltip properties:

  • tooltip: A string with the content for the tooltip. Can contain markdown.
  • tooltipOptions: A object with the following keys:
    • target: DOM id of target
    • direction: Direction of the tooltip. Can be "top", "bottom", "left" or "right". (default "right")
    • trigger: Decides when the tooltip will be shown: "hover" or "click". (default "hover")
    • delay: Object with the keys show and hide. Sets the delay in ms to show/hide the tooltip. (default { show: 750, hide: 150 })
    • autoClose (number): Close the tooltip after x milliseconds after opening. (default 0)
    • width: Set a fix tooltip width. (default "auto")
    • maxWidth: Set a fix max width. (default "700px")
    • size: Set the tooltip font size: "small", "default" or "large". (default "default")
    • offset (number): Set the distance to target id in px. (default 0)
    • closeOnClick (boolean): Closing tooltip on click (default true).
    • class: Add a additional tooltip class.
    • interactive: If hover, tooltip won't hide on mouseover. (default true)

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.
  • 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'.

  • tooltip: Shows a tooltip on label / label icon.

  • tooltipOptions: See details under Tooltip component.

  • 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 which must be set in all existing nodes. Just follow these steps:

  • You have to add "_version" 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.
  • Handling legacy properties: If you remove a value from the node default object and need the value from the existing nodes, add them via the addLegacyProperties function. With a version check you get one last time access to the value to add them to another property. After the first deploy the legacy property will be deleted from the Node-RED json file.
    
    // update existing node values => version === currrent node version
    const clientUpdate = (version, node) => {
      // version = {major: 1, minor: 2, patch: 3, tag: 'beta-1', string: '1.2.3-beta-1', aggregated: 1002003, parse = function('string') }
      // version below 1.2.0
        if (version.aggregated < version.parse('1.2').aggregated) {
        // overwrite all node names
        node.name = "my new name"
      }
      
      // lower than 2.1.3
      if (version.aggregated < version.parse('2.1.3').aggregated) {
        // node.myProp is depreceated and is now node.anotherProp
        node.anotherProp = node.myProp // Attention: Add my prop in the addLegacyProperties function to enable getting the value a last time. 
      }
      return node
    }
    
    // add temporarily node default keys => version === currentVersion
    // this function is handy if you rename or split old values
    const addLegacyProperties = (version) => {
      const legacyProps = []
      if (version.aggregated < version.parse('2.1.3').aggregated) {
        legacyProps.push('myProp')
      }
      return legacyProps
    }
    
    module.exports = { 
      clientUpdate,
      legacyProps
    }
    
    • 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._version
      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...)

Dependencies (6)

Dev Dependencies (1)

Package Sidebar

Install

npm i svelte-integration-red

Weekly Downloads

421

Version

2.0.1

License

MIT

Unpacked Size

677 kB

Total Files

53

Last publish

Collaborators

  • 2weltenchris
  • meijey