Tutorials
Writing your first app
Now that you installed Terminosaurus, it's time to write your first app. Let's create an index.ts
file:
Basic usage
import {runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.} from 'terminosaurus';
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.(screenscreen: TermScreen
=> {
// For now, nothing else.
});
In this file we imported the run
function from the terminosaurus
package and used it to automatically create a screen and run the app. You should prefer using this function over instantiating a TermScreen
yourself, as it also asynchronously loads the required WASM modules, and wait for the application to complete before returning.
Showing text
We're now going to start printing some text to the terminal. Replace the run
function with the following:
import {TermTextclass TermText
, runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.} from 'terminosaurus';
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.(screenscreen: TermScreen
=> {
const textconst text: TermText
= new TermTextnew TermText(): TermText
();
textconst text: TermText
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(screenscreen: TermScreen
.rootNodeTermScreen.rootNode: TermElement
);
textconst text: TermText
.setTextTermText.setText(content: string): void
(`Hello world`);
});
If you run this script, you'll see your text appear then stay on screen until you press Ctrl+C to exit the application.
Styling elements
That's a good start, but let's implement something a little more fun. What about a progress bar? To do that, let's create a new file called progress.ts
that displays just a white bar:
import {TermElementclass TermElement
, colorfunction color(rawValue: keyof typeof colorNames | string): {
front: string;
back: string;
} | undefined
, lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
, runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.} from 'terminosaurus';
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.(screenscreen: TermScreen
=> {
const barconst bar: TermElement
= new TermElementnew TermElement({ textLayout }?: {
textLayout?: TextLayout | null | undefined;
}): TermElement
();
barconst bar: TermElement
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(screenscreen: TermScreen
.rootNodeTermScreen.rootNode: TermElement
);
barconst bar: TermElement
.styleTermElement.style: Ruleset
.resetRuleset.reset: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
backgroundColorbackgroundColor?: symbol | {
front: string;
back: string;
} | undefined
: colorfunction color(rawValue: string): {
front: string;
back: string;
} | undefined
(`white`),
heightheight?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
(1),
});
});
Take note of how we assigned style properties to the bar
element. Terminosaurus implements a significant subset of CSS properties, and you see it in action here.
Live updates
Let's now add some interactivity to this bar; the way Terminosaurus works, all changes performed on your elements will be automatically reflected on the screen. Knowing that, animating the bar's width is just a matter of periodically updating width
:
import {TermElementclass TermElement
, colorfunction color(rawValue: keyof typeof colorNames | string): {
front: string;
back: string;
} | undefined
, lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
, runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.} from 'terminosaurus';
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.(screenscreen: TermScreen
=> {
const barconst bar: TermElement
= new TermElementnew TermElement({ textLayout }?: {
textLayout?: TextLayout | null | undefined;
}): TermElement
();
barconst bar: TermElement
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(screenscreen: TermScreen
.rootNodeTermScreen.rootNode: TermElement
);
let widthlet width: number
= 0;
barconst bar: TermElement
.styleTermElement.style: Ruleset
.resetRuleset.reset: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
backgroundColorbackgroundColor?: symbol | {
front: string;
back: string;
} | undefined
: colorfunction color(rawValue: string): {
front: string;
back: string;
} | undefined
(`white`),
widthwidth?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
.rellength.rel(rawValue: string): {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
(`${widthlet width: number
}%`),
heightheight?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
(1),
});
const intervalconst interval: NodeJS.Timeout
= setIntervalfunction setInterval<[]>(callback: () => void, ms?: number | undefined): NodeJS.Timeout (+2 overloads)
Schedules repeated execution of `callback` every `delay` milliseconds.
When `delay` is larger than `2147483647` or less than `1`, the `delay` will be
set to `1`. Non-integer delays are truncated to an integer.
If `callback` is not a function, a `TypeError` will be thrown.
This method has a custom variant for promises that is available using `timersPromises.setInterval()`.(() => {
widthlet width: number
= widthlet width: number
< 100 ? widthlet width: number
+ 1 : 0;
barconst bar: TermElement
.styleTermElement.style: Ruleset
.setRuleset.set: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
widthwidth?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
.rellength.rel(rawValue: string): {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
(`${widthlet width: number
}%`),
});
}, 16);
});
Everything together
Having a progress bar is nice, but it's not very useful if it doesn't represent anything. Let's style it a little bit and add some text to it:
import {
StyleValuesconst StyleValues: {
Inherit: symbol;
Length: {
Zero: {
value: number;
isRelative: boolean;
yoga: number;
};
One: {
value: number;
isRelative: boolean;
yoga: number;
};
Auto: {
value: number;
isRelative: boolean;
yoga: number;
};
AutoNaN: {
...;
};
Infinity: {
...;
};
};
... 12 more ...;
WhiteSpace: {
...;
};
}
,
TermElementclass TermElement
,
TermTextclass TermText
,
colorfunction color(rawValue: keyof typeof colorNames | string): {
front: string;
back: string;
} | undefined
,
lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
,
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.,
} from 'terminosaurus';
runfunction run(cb: (screen: TermScreen) => void | undefined): Promise<number> (+1 overload)
Create a new TermScreen and run the provided callback. Return a promise that resolves when the screen is closed.(screenscreen: TermScreen
=> {
const containerconst container: TermElement
= new TermElementnew TermElement({ textLayout }?: {
textLayout?: TextLayout | null | undefined;
}): TermElement
();
containerconst container: TermElement
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(screenscreen: TermScreen
.rootNodeTermScreen.rootNode: TermElement
);
let widthlet width: number
= 0;
const labelconst label: TermText
= new TermTextnew TermText(): TermText
();
labelconst label: TermText
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(containerconst container: TermElement
);
labelconst label: TermText
.setTextTermText.setText(content: string): void
(`Loading in progress`);
const barContainerconst barContainer: TermElement
= new TermElementnew TermElement({ textLayout }?: {
textLayout?: TextLayout | null | undefined;
}): TermElement
();
barContainerconst barContainer: TermElement
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(containerconst container: TermElement
);
const barconst bar: TermElement
= new TermElementnew TermElement({ textLayout }?: {
textLayout?: TextLayout | null | undefined;
}): TermElement
();
barconst bar: TermElement
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(barContainerconst barContainer: TermElement
);
const timeconst time: TermText
= new TermTextnew TermText(): TermText
();
timeconst time: TermText
.appendToTermNode<TermElement>.appendTo(node: TermElement): void
(containerconst container: TermElement
);
timeconst time: TermText
.setTextTermText.setText(content: string): void
(`${widthlet width: number
}%`);
containerconst container: TermElement
.styleTermElement.style: Ruleset
.resetRuleset.reset: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
flexDirectionflexDirection?: symbol | {
yoga: 2;
} | {
yoga: 3;
} | {
yoga: 0;
} | {
yoga: 1;
} | undefined
: StyleValuesconst StyleValues: {
Inherit: symbol;
Length: {
Zero: {
value: number;
isRelative: boolean;
yoga: number;
};
One: {
value: number;
isRelative: boolean;
yoga: number;
};
Auto: {
value: number;
isRelative: boolean;
yoga: number;
};
AutoNaN: {
...;
};
Infinity: {
...;
};
};
... 12 more ...;
WhiteSpace: {
...;
};
}
.FlexDirectiontype FlexDirection: {
Row: {
yoga: 2;
};
RowReverse: {
yoga: 3;
};
Column: {
yoga: 0;
};
ColumnReverse: {
yoga: 1;
};
}
.Rowtype Row: {
yoga: 2;
}
,
});
barContainerconst barContainer: TermElement
.styleTermElement.style: Ruleset
.resetRuleset.reset: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
marginLeftmarginLeft?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
(2),
marginRightmarginRight?: symbol | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
(2),
flexGrowflexGrow?: number | symbol | undefined
: 1,
flexShrinkflexShrink?: number | symbol | undefined
: 1,
});
barconst bar: TermElement
.styleTermElement.style: Ruleset
.resetRuleset.reset: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
backgroundColorbackgroundColor?: symbol | {
front: string;
back: string;
} | undefined
: colorfunction color(rawValue: string): {
front: string;
back: string;
} | undefined
(`white`),
widthwidth?: symbol | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
.rellength.rel(rawValue: string): {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
(`${widthlet width: number
}%`),
heightheight?: symbol | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
(1),
});
const intervalconst interval: NodeJS.Timeout
= setIntervalfunction setInterval<[]>(callback: () => void, ms?: number | undefined): NodeJS.Timeout (+2 overloads)
Schedules repeated execution of `callback` every `delay` milliseconds.
When `delay` is larger than `2147483647` or less than `1`, the `delay` will be
set to `1`. Non-integer delays are truncated to an integer.
If `callback` is not a function, a `TypeError` will be thrown.
This method has a custom variant for promises that is available using `timersPromises.setInterval()`.(() => {
widthlet width: number
= widthlet width: number
< 100 ? widthlet width: number
+ 1 : 0;
barconst bar: TermElement
.styleTermElement.style: Ruleset
.setRuleset.set: (propertyValues: Map<"flex" | "left" | "right" | "display" | "alignContent" | "alignItems" | "alignSelf" | "flexDirection" | "position" | "inset" | "insetX" | "insetY" | "top" | "bottom" | ... 43 more ... | "pointerEvents", any> | Partial<...>) => boolean
({
widthwidth?: symbol | {
value: number;
isRelative: boolean;
yoga: string;
} | {
value: number;
isRelative: boolean;
yoga: number;
} | {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
: lengthfunction length(rawValue: string | number): {
value: number;
isRelative: boolean;
yoga: number;
} | undefined
module length
.rellength.rel(rawValue: string): {
value: number;
isRelative: boolean;
yoga: string;
} | undefined
(`${widthlet width: number
}%`),
});
timeconst time: TermText
.setTextTermText.setText(content: string): void
(`${widthlet width: number
}%`);
}, 16);
});