Tabris.js 3.2 brings camera support, new data binding features and more
UPDATE: A patch release (3.2.1) fixing issues with cordova plug-in support is now available.
We are happy to announce Tabris.js 3.2, the first version with built-in camera support – no plug-ins needed. We also improved data binding to better support the MVVM programming pattern. Other changes include new properties on
TextInput
and using blobs as images. Finally, the documentation has been improved, most notably offering better navigation.
Have a look at the official release notes for the full list of changes.
New Widget “CameraView”
Tabris.js 3.2 adds the ability to take images via device camera. The “device” object provides a list of cameras, which can be set on CameraView to show a live preview feed. To capture an image, simply call the asynchronous camera.captureImage()
method, which returns a Blob
containing a JPEG. The existing permissions API can be used to obtain access to the camera.
Minimal Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const camera = device.cameras[0]; permission.withAuthorization('camera', () => camera.active = true, () => console.log('"camera" permission is required.'), (e) => console.error(e)); contentView.append( <Stack stretch> <CameraView stretchY camera={camera}/> <Button text='Take picture' onSelect={captureImage}/> </Stack> ); async function captureImage() { const {image} = await camera.captureImage({flash: 'auto'}); // do something with the "image" blob... } |
With the Tabris.js 3.2 Developer app you can try a larger example right here: camera-advanced.tsx
Blob and BitmapImage as Generic Images
A compressed image (jpeg, png) obtained as a Blob
object – for example via fetch
or Camera
– can now be used anywhere as an ImageValue.
Minimal Example:
1 2 3 |
const response = await fetch('http://foobar/image.png'); const blob = await response.blob(); contentView.append(<ImageView stretch image={blob}/>); |
The same is true for BitmapImage
objects, which can be created from Blob
and ImageData
. That way the image is already in memory and its size already known before it is used in the UI.
This feature will become even more powerful with BitmapImage API extensions in future Tabris.js releases.
New TextInput properties
The messageColor property lets you control the color of the message placeholder text independently from the input text.
On Android only keyboardAppearanceMode can be used to prevent the on-screen keyboard from popping up when a TextInput is focused, or only when it is focused by touch.
Data Binding
The JSX/decorators based data binding API (TypeScript only!) has been extended to allow bindings between widgets and non-widget (“plain”) objects, including change detection. The tabris init
command can now also create projects using this feature, simply choose the option “Model-View-ViewModel” when prompted for “Example Code.” Make sure the CLI is up to date before doing so (3.2.0).
One-Way Bindings
Any instance of a class using the @property decorator can be used for bindings. One-way bindings to such object are declared via JSX. The syntax for this remains unchanged, except that it is now possible to bind to deeply nested properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@component export class ExampleComponent extends Composite { @property public myObject: Model; constructor(properties: Properties<ExampleComponent>) { super(); this.set(properties).append( <Stack stretch> <ProgressBar bind-selection='myObject.someNumber'/> <TextView bind-text='myObject.otherModel.someString' text='Placeholder'/> </Stack> ); } } |
The above example applies values of myObject
properties to ProgressBar
and TextView
properties. If the source values are changed, or the entire myObject
object is replaced, the widget properties are updated accordingly. Direct changes to the widget properties will not be propagated to myObject
, as this is a one-way binding.
Two-Way Bindings
Two-way bindings to plain objects are declared via the @bind or the @bindAll decorator (which is a shorthand). The decorators take a parameter object mapping the property of the object to any property of any component-internal child (identified via its id):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@component export class ExampleComponent extends Composite { @bindAll({ myText: '#input1.text', myNumber: '#input2.selection' }) public model: Model; constructor(properties: Properties<ExampleComponent>) { super(); this.set(properties).append( <Stack> <TextInput id='input1' text='Fallback Text'/> <Slider id='input2'/> </Stack> ); } } |
This applies values of model properties
to TextInput
and Slider
properties and vice versa.
Updated Plug-Ins
The following plug-ins have been updated to work with Tabris.js 3.2:
- tabris-plugin-maps (6.0.0)
- tabris-plugin-firebase (4.0.0)
- tabris-plugin-barcode-scanner (3.0.0)
That’s all Folks
As always we are looking forward to your feedback on our public slack channel. If you have feature requests or something does not behave as expected, you can also open an issue on GitHub.
Get Started with Tabris.js 3.2
- Install the Tabris.js developer app on your device. Links below.
- Try out the snippets bundled in the app, or edit and run them via the Tabris.js Playground.
- Install the 3.2 Tabris CLI on your machine:
npm install -g tabris-cli@3.2.0
- Type
tabris init
in an empty directory – this will create a simple example app - Type
tabris serve
and load it in the developer app - Check out the 3.2 documentation
Feedback is welcome!
Want to join the discussion?Feel free to contribute!