Tungsten

Components

Tungsten focusses on class based components. The reason for this is simple - classes and objects in programming languages were designed to be able to create self contained objects (components) based on templates (component types). Class based components are easier to code within the framework, and easier for developers to understand deeply, given that they follow ordinary Object Oriented Programming principles. There was no need to reinvent the wheel here.

Function based components have both pros and cons. They are partly supported, and increased support is planned in the future, most importantly to support React components.

Component Choices

The framework currently has 3 base components to choose from.

SimpleComponent takes 2 optional type arguments, Props and RouteData. Props must be an object, and describes the props the component can receive. RouteData specifies the type of data the component can receive from a route data function (more on that in the routing section). SimpleComponents cannot have state.

class MyComponent extends SimpleComponent<?Props extends object, ?RouteData>

StatefulComponent has 2 required type arguments, Props and State, and 1 optional type argument RouteData. A state field must be defined matching the type of the State type argument. Explicitly type annotating the state field with the State type is recommended to engage strictly type control by TypeScript. StatefulComponents always have state. Props type should be set to 'object' if there are none.

class MyComponent extends StatefulComponent<Props extends object, State extends object, ?RouteData>

Component is a multi purpose base class that has 3 optional type arguments, Props, State, RouteData. Using state here is optional. Due to TypeScript limitations, these components will not give type errors if you forget to define the state field. That aside, they are perfectly functional for both stateful and stateless components.

class MyComponent extends Component<?Props extends object, ?State extends object, ?RouteData>

A class based component

import { StatefulComponent } from 'tungsten'
type Props = object
type State = {
count: number
}
export class Counter extends StatefulComponent<Props, State> {
state = {
count: 0
}
increment = () => this.state.count++
content = () => (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.increment}>+</button>
</div>
)
style = Sass`
div
background: black
h1
color: white
button
color: white
background: purple
`
}

'this.props' and 'this.state' are also available as arguments to the init, content and other methods. This is nicer in non-typescript mode though.

content = (_: Props, {count}: State) => (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.increment}>+</button>
</div>
)
or
content = (props: Props, state: State) => (
<div>
<h1>{state.count}</h1>
<button onClick={this.increment}>+</button>
</div>
)

Function based component

Function based components are available for simply components, but are very much taking a back seat when it comes to advanced features. Classes and class instances are programming devices designed to creating templates and instances of those templates, with internal state - which is exact what we are doing with components, so I don't see the need to focus on building components with tool (functions and hooks) not designed for it.

Adding support for all features in function based components is never-the-less desirable in the long term.

type ButtonProps = {
text: string
onClick?: (event: ButtonMouseEvent) => void
}
export function Button({text, onClick}: ButtonProps) {
return <button onClick={onClick}>{text}</button>
}
Button.style = Sass`
button
background: blue
border-radius: 1em
`

Content, Style, Script

Tungsten follows the tradition of separate content, style and script. In general, scripting is handled in the top part of components, content is specified in the content method, and styles are in the component stylesheet.

The 'style' prop is available as in react, taking a JavaScript object of styles. A 'css' prop is also available taking a plain css string.

<span style={{color: 'red'}} css="font-size: 1.5em;">some text</span>