Accursed
blessed contributions, extensions, typings, documentation and apps of mine
Summary: I discovered blessed, an awesome library for developing command line UI, but unfortunately is a discontinued project a dn has poor documentation.
Instead of cloning the project, here I try to develope missing parts, learn, document, type and find issues, but on top of it.
So I'm learning, documenting prototyping and researching. The following is a summary of work done.
- Demos
- JSX
- Attributes
- IntrinsicElements
- Class Elements and Function elements
- Event handlers (function attributes)
- blessed events supported 100% as JSXAttribtues
- Hight level event handlers
- JSX Expressions
- Refs
- Virtual Elements
- JSX Text
- blessed-contrib
- Rendering Component own children
- Fragments
- Hooks into React.crateElement
- specs
- My blessed contrib widgets, utilities and JSX Components:
- Apps
- Typings:
- Documentation:
- How-to bless documents
- TODO & ISSUES & Ideas
npm run start-emojis-search
npm run start-gallery
npm run start-cli-fonts-gallery
- JSX/TSX support for all blessed components plus some of mine
Simple, implementation of React.createElement to render JSX to blessed elements.
Small but well-tested logic based on previous acquired knowledge in project https://github.com/cancerberoSgx/jsx-alone
Tip for JSX newcomers, JSX attributes are typed. If a blessed option accept a number or a boolean then the attribute must be also. Example: the following two expressions are equivalent:
const el = blessed.listbar({
parent: screen, mouse: true, width: '88%',
height: 3, style: { selected: { bg: 'magenta' }, }
})
const el = React.render(<blessed parent={screen} mouse={true} width="88%" height={3} style={{bg: colors.green}}})
TIP for JSX newcomers: you can use object like syntax mixed with attribute syntax if more confortable and use spread expressions like this if you want:
const commonOpts = { keys: true, mouse: true, clickable: true, border: 'line'...
const el = React.render(<Div {...commonOpts} width="100%" border="line"
style={...commonStyles, {border: {...}, hover: {...}})...
Intrinsic elements are the building blocks os a JSX implementation and in thi case those are the blessed build in elements like button, bo, listbar, etc. Their tags **start with lower case.
Mostly all blessed element types are supported by this library
Class elements and function elments for creating custom tags is fully supported. Do it as you would normaly do:
In the following example we extend Component to create a new Class Element, but you don't have to, just make sure its constructor accepts a props object parameter and it has a render() method that returns the JSX.Element:
interface Props {name, colors: string[]}
class ListTable extends Component<Props> {
render() {
return <Div>
Hello {this.props.name}, so this are the colors: {this.props.colors.map(c=><Color color={c}/>)}
</Div>
}
}
In the following example, we create a new Element that will print children text with bold and optionally color styles.
interface Props = { children: string | string[]; color?: string }
function Strong(props: Props) {
return (
<text content={format(asArray(props.children || []).join(' '), ['bold', props.color].filter(notUndefined))}
/>
)
}
- work 100%
- are bind() to the element reference
JSX syntax, in event-related methods like like on() or key(), etc are supported via attributes. There is no syntax mapping at all, just straight forward method call, for example:
textarea.key('f', (ch, key) => { ... }]}
equivalent to
´´ç
<textarea key={['f', (ch, key) => { ... }]}
If you notice some differences here, is ony because typings are insufficient, but there is no mapping/wrapping in these.
Although these are typed are kind of ugly because must be arrays. this is why also there are supported nicer "artificial" event handlers:. JSX-HTML event handler syntax more practical in the markup:
onClick, onChange, onRender, onKeyPressed
so attributes are easy to write (just a function).
Like with HTML - React - the event object of these hight level handlers have currentTarget
property that references the element that triggered the event. Is particularly useful for change events in input elements:
<checkbox content="Collapsed" checked={false}
onChange={e => toggleCollapsed(e.currentTarget.parent as any, true)}
<button onClick={e => this.installCollapsible(e.currentTarget, { collapsedHeight: 4 })}
<layout onRender={e => this.installCollapsible(e.currentTarget, { collapsedHeight: 4 })}
(currently only supported for Checkbox and subclasses) - WIP
<checkbox content="Collapsed" checked={false}
onChange={e => toggleCollapsed(e.currentTarget.parent as any, true)}
export class Categories extends Component<Props> {
render() {
return <Div>Choose a category, select and emoji and press [ENTER] for details.<Br />
<list {...commonOptions()} height={'20%'}
items={getCategoryNames()}
onSelect={e => this.selected(e)}
/>
...
Any expression often used to declare conditions aor iterate inside JSX Expressions are supported .
Falsy values won't be rendered so you can write expressions like the following
{ condition && <box...}
{ arr.map(a => <box...)}
{ condition ? <box... : <box...}
Implements Reac refs adding extra features.
const screen = blessed.screen({ smartCSR: true, log: 'log.txt', fullUnicode: true })
...
// create a RefObject before rendering. use the Type parameter to declare it will reference a button
const ref1 = React.createRef<Button>()
// append some elements to the screen.has a ref iption and its value is the object we jsut cerwated.)
const app = <box><button ref={ref1} content="click" onClick={e =>
expect(!ref1.current).isNotDefined() // before render the variable will be undefined
// after rendering the screen, we will be able to access the button using the variable without manually searching g for it.
blessed.screen.render()
// ... when the button finish rendering
ref1.current!.content = "'changed3"
ref1.current!.screen.render()
...
ref1.press()
...
Also React.createRef()
accepts a callback that provides the new element:
class App extends Component {
protected container: Box
render(){
return <box ref={React.createRef(current=>this.container = current)}>
...
</box>
}
}
- Unique feature - not even existent in React
- Let component authors declare element's children props that won't be rendered at all.
- Useful to define complex component API as markup and then render another thing that implements it.
- See spec
- See guides/virtual-elements.md
- Examples of components that heavily use virtual elements to define their APIs:
- (src/jsx-components/tabPanel.tsx)[TabPanel]
- (src/jsx-components/listTable.tsx)[ListTable]
- (src/jsx-components/listBar.tsx)[ListBar]
By default, for each JSXText node found, a new blessed.text
is created.
THis means that JSX like
<box> Hello here I'm writing <button onClick={this.m}>think this is invalid</button> some <box>in the middle</box> and a tail</box>
will be actually rendered as something like this
<box><text content=" Hello here I'm writing"/><button onClick={this.m}><text content="think this is invalid"/></button><text content=" some "/><box><text content="in the middle"/></box><text content=" and a tail"/></box>
Think on the TREE of blessed elements that will be generated). Also buttons will end up with a text inside. Below are more details, Probably a second implementaiton using parent's content attribute will be implemented and both will be available thorough configuration.
**blessed-contrib widgets should be very easy to suuport, but right now I?m focusing on the framework and my own widgets tools and documentation, and hadent much time. They will be in time, probably in a separate project project.
- In custom components with children must render them using an expression like
<MyComp {this.props.children} other="options"/>
Not supported yet :()
- WIP : api to extend the rendering process
- React object oprovide with some addLikstener in interesting moments of the rendering tha tusers can use to modify the render process and even interrupt / modify the flow but right now only sketches... working on that...
-
blessed has no specs - seems they (did) run them manually. I'm writing specs with my new feaytures. Some I use cli-driver to test the tire flow from the real command line automation, and other, I just render the widgets and assert against the screen content.
-
testing blessing APIs alone , even create custom elements: spec/blessedSpec.tsx
-
jsx related: spec/jsxSpec.tsx
-
using cli-driver to spawn a program and automate it spec/jsxSpec.tsx
- focus manager
- collapsible element
- node operations (ascendants, descendants, siblings, etc)
- showInModal()
- layout renderer with html like semantics display: block, overflow: hidden
- TreeView
- Maximize/Restore
- BorderBox
- EditorWidget from Slapeditor project. I updated dependencies and documented EditorWidget which is great. Made easy to use API that automatically highlights and focus the editor.
visibleOnAncestorFocus
Automatically shows/hides descendants when ancestors (or any of its descendants) are focusedscreenLogger
simple logger visual logger API�rowColumnResize
: adds small controls to resize rows or columns, easy to use with the keyboard and non invasive since the¥ only appear when column/row or descendant have focus.
ListTable
TabPanel
<If>
conditions with markup - not so useful but interesting....Button2
ShowIf
Collapsible
Select
Columns
Accordion
Autocomplete
OptionsProvider
Maximize
- wrapping an element with it will show a "maximize/restore" buttons floating at top-left<editor>
component to easy render editor-component from slap editor project.<ListBar>
- listbar semantics with jsx markupcicks
to listen for multiple clicks (double click)
-
apps/emojis-search : a unicode data table explorer. Test blessed performance by letting ht user interactively navigate/search, etc the FULL unicode charset .
-
accursed gallery, spec/blessed/gallery/LayoutDemo.tsx I tried to use these tools to build a interactive playground with examples. WIP
-
json-cat: CLI app that render json streams with a tree view. Supports async render when streams are loading, filtering by text or json JSONPath.
-
editar: CLI text-editor, inspired on vscode, based on editor-widget (independent form slap-editor)
-
https://github.com/cancerberoSgx/demos/tree/master/docs/typescript-ast-explorer - explore a TypeScript project AST , visualize together with sources code and even apply refactors.
Also I think I've enhanced a lot the blessed.d.ts (TypeScript type declarations). ALthough the work from Definetely Typed I started from was very good, I did some refactoring so option types doesn't get too restrictive, I added lots of jsdoc comments and snippts to classes and methods and declared lots of internal methods. I want this types to be used by users extending the library (class MyElement extends blessing.widget.Box {}) and they need visibility to important methods, no matter if those are not meant to be published. I marked those with @internal tab. Also included typings for blessed-contrib but those I didn't modify so much.
the typings already existing in DefinitelyTypes had more or less all the descriptions in blessed README. I added a lot from program.js, snippets and make sure it all blessed/tests.js compile OK with the types (which didn't). Also using typedoc I'm truing to generate html and markdown output of this so I can share with others.
guides/blessed-extending-element-typescript.md explain how to extend blessed Element class to create a new Widget type, using TypeScript, in a type checked experience.
guides/browserify.md explain how to run blessed programs in the browser using browserify.