Block properties
Block properties store settings and information for a block in the form definition. The builder part of a block informs the builder about the properties that should be stored in the definition. The runner part of a block can then use those properties for rendering (or operating) the block.
🏗️ Properties in the builder part
The block properties that need to be stored in the form definition are defined in the builder part of the block. To include a property in the form definition, it needs to be decorated with the @definition
decorator. This assures the property is automatically saved to and retrieved from the form definition.
Basic usage
The following example shows the basic usage of this decorator:
import { tripetto, definition, NodeBlock } from "@tripetto/builder";
@tripetto({
type: "node",
identifier: "example",
label: "Example",
icon: "data:image/svg+xml;base64,PHN2ZyAvPg=="
})
class ExampleBlock extends NodeBlock {
@definition
exampleProperty?: boolean;
}
Supply type information
You can extend the decorator with detailed type information about the decorated property. This type information is used by the builder to transfer values between blocks that implement the same property. This happens when the user switches to another block type for a certain node. See the @definition
for the available options. Here is an example where detailed type information is supplied:
import { tripetto, definition, NodeBlock } from "@tripetto/builder";
@tripetto({
type: "node",
identifier: "example",
label: "Example",
icon: "data:image/svg+xml;base64,PHN2ZyAvPg=="
})
class ExampleBlock extends NodeBlock {
@definition("boolean", "optional")
exampleProperty?: boolean;
}
🏃 Properties in the runner part
The runner part only consumes (reads) the block properties from the form definition. The block property types can be supplied to the class declaration of the block in the runner part. That makes the properties (with the right types) available in the props
field of the block class. The following example shows how to do this:
import { tripetto, NodeBlock } from "@tripetto/runner";
@tripetto({
type: "node",
identifier: "example"
})
class ExampleBlock extends NodeBlock<{
exampleProperty?: boolean;
}> {
// Block implementation here
}
💂 Type guarding parts
It is possible to define a shared properties interface that serves as a code contract between the builder and runner part of the block. This guards the use of the properties in both parts of the block. To implement that, you first need to define the interface for the block properties:
export interface IExampleBlock {
exampleField1: string;
exampleField2?: number;
}
Builder part
Now you can use this interface in the builder part, to assure that part implements all the properties correctly:
import { tripetto, definition, NodeBlock } from "@tripetto/builder";
import { IExampleBlock } from "./block-properties";
@tripetto({
type: "node",
identifier: "example",
label: "Example",
icon: "data:image/svg+xml;base64,PHN2ZyAvPg=="
})
class ExampleBlock extends NodeBlock implements IExampleBlock {
@definition("string")
exampleField1 = "";
@definition("number", "optional")
exampleField2?: number;
}
Runner part
In the runner part, we can now simply supply the interface to the block class declaration so the props
field derives the block property types from the properties interface:
import { tripetto, NodeBlock } from "@tripetto/runner";
import { IExampleBlock } from "./block-properties";
@tripetto({
type: "node",
identifier: "example"
})
class ExampleBlock extends NodeBlock<IExampleBlock> {
// Block implementation here
}
Using collections
When your block contains a collection, make sure to omit that property in the builder part. The reason for this is that the collection type on the builder part is different from that on the runner part. For example, consider this interface:
export interface IExampleItem {
name: string;
}
export interface IExampleBlock {
items: IExampleItem[];
exampleField1: string;
exampleField2?: number;
}
In the builder part we need to omit the items
property because the type in the class is different from the type declared in the interface:
import { _, tripetto, definition, name, Collection, NodeBlock } from "@tripetto/builder";
import { IExampleBlock, IExampleItem } from "./block-properties";
class ExampleItem extends Collection.Item<ExampleBlock> implements IExampleItem {
@definition
@name
name = "";
}
@tripetto({
type: "node",
identifier: "example",
label: "Example",
icon: "data:image/svg+xml;base64,PHN2ZyAvPg=="
})
class ExampleBlock extends NodeBlock implements Omit<IExampleBlock, "items"> {
items = Collection.of<ExampleItem, ExampleBlock>(ExampleItem, this);
@definition("string")
exampleField1 = "";
@definition("number", "optional")
exampleField2?: number;
}