Skip to content

Releases: eclipsesource/tabris-js

Version 3.9.0

09 Nov 09:48
Compare
Choose a tag to compare

Release Notes

Crypot API

  • Support of Elliptic Curve Diffie-Hellman (ECDH) P-256 cryptography
  • ECDH shared secret deriviation
  • HKDF key deriviation
  • AES-GCM encryption & decryption

TypeScript

Now compatible with TypeScript 4.8.

Version 3.8.0

05 Oct 12:58
Compare
Choose a tag to compare

Threads.js compatibiltiy

Various compatibility issues have been fixed so that the Tabris.js Worker implementation is now compatible with threads.js. In addition, console logs from the worker now also appear on the remote (CLI) developer console.

API

CollectionView

The new fastScroll property enables the fast scroll thumb in Android that can be dragged to quickly scroll through the list of items. The feature is enabled by default in iOS devices starting from version 13 and cannot be disabled.

More powerful functional components

Manipulating the data object available on all widgets will now make the widget emit dataChanged events. This allows creating functional components displaying mutating models instead of static data.

It also works with any other object that emits change events, including any instance of ObservableData (new in 3.8) or object using the @prop decorator. Changes in nested objects are also recognized.

Better MVVM support

Binding viewmodels via the @bindAll decorator now supports value conversion. Combined with the new change event propagation feature this also allows bindings to nested properties, e.g. person.address.street.

Binding multiple widget properties to one viewmodel property is now also supported.

And finally, views can now react to viewmodel events, for example to trigger an animation.

tabris.Input

The new input service object allows intercepting all pointer events on the app window, regardless of the targeted widget. Supported are down, up, move, and cancel events.

Android

Improved performance

The communication between JavaScript and native code has been optimized.

Update to Cordova 9

Tabris now uses Cordova 9 to build apps targeting android.

Version 3.7.2

Version 3.7.1

16 Dec 15:28
Compare
Choose a tag to compare

Fixed some memory leaks

Version 3.7.0

01 Dec 17:16
Compare
Choose a tag to compare

Security

Authentication

SubtleCrypto

Module System

New method Module.addPath

Module.addPath allows to define path aliases to make imports more consistent. It supports the TypeScript compiler "paths" option.

New method Module.define

Module.define can create new modules at runtime, for example to dynamically override file modules.

Widgets

CollectionView reveal with offset

beforeTextChange

Event System

Observables

Tabris now provides an implementation of the proposed Observable API. It has been integrated in to the event system so you can get observables for specific events (e.g. button.onSelect.subscribe(...)), property values (via change events, e.g checkBox.onCheckedChanged.values.subscribe(...)), or any object emitting Tabris.js change events (Observable.mutations(widget).subscribe(...)). It is also RxJS compatible via their from method:

rxjs.from(button.onSelect)
  .pipe(debounceTime(100))
  .subscribe(ev => ...);

Declarative UI

"Set" renamed to "Setter" to avoid confusion

Set was introduced in 3.6 as a helper function for use with composite.apply. When imported it shadowed the Set class built in to JavaScript. While this was considered acceptable at the time, it caused more issue than inticipated, so it was renamed to Setter. For backwards compatibility the function is also still exported as Set as an alias, but only documented as Setter.

"apply" is now declarative, supports new syntax

The "apply" method of Composite can now be invoked in a declarative way using either the attribute apply or the new JSX element <Apply>. It can also, in addition to the established syntax, be given an array of Setter elements (or a single one) for shorter syntax with better tooling support. This is a very convinient way to remove repetition in your UI code akin to CSS in HTML.

This example uses the apply attribute to create 3 TextView widgets that share a set of properties:

contentView.append(
  Composite({
    padding: 8,
    apply: Setter(TextView, {
      top: 'prev() 10',
      background: '#66E',
      textColor: 'white',
      font: '24px'
    }),
    children: [
      TextView({text: 'Hello'}),
      TextView({text: 'Blue'}),
      TextView({text: 'World'})
    ]
  })
);

The apply method/attribute/element can now also react to any property change of the widget it is called on. This can be used to write concise custom or functional components that update their content due to a change in any of their properties.

JSX element "Setter"

The Setter function can also be used as a JSX element to set any attribute its parent. This includes listeners and callbacks, so for example the CollectionView JSX element could now contain it's own cell factory:

  <CollectionView stretch itemCount={people.length} cellHeight={256} updateCell={updateCell}>
    <Setter target={CollectionView} attribute='createCell'>{() =>
      <Composite onTap={handleTap}>
        <ImageView top={16} centerX={0} width={200} height={200}/>
        <TextView left={30} top='prev() 16' right={30} alignment='centerX'/>
      </Composite>}
    </Setter>
  </CollectionView>

In general it's useful in any scenario where an attribute value would otherwise be too long for inlining.

Decorators

One-Way data binding via "@Bindall"

The "@Bindall" decorator can now be used to create one-way data bindings (in any direction) between a model and a child of a custom component, or the custom component itself. This is an alternative to the JSX based on-way data binding that may be more consistent when using the MVVM pattern.

Property based Dependency Injection

The "@Inject" decorator can now also be applied to properties, not just constructor parameters. This can be helpful to resolve circular dependency issues and result in an overall less cluttered constructor.

Version 3.6.1

01 Oct 15:14
Compare
Choose a tag to compare

This patch release only updates the npm module and Android platform. The iOS platform, CLI and developer apps remain unchanged. The new npm module still works with 3.6.0 platforms and vice versa.

Version 3.6.0

31 Jul 12:56
Compare
Choose a tag to compare

API

New Widget "PdfView"

Tabris 3.6 introduces a new widget specifically for displaying PDF documents. The file can be loaded from the local file system or a Blob object. Since this widget uses native rendering, scrolling and zooming the UI is very resonsive.

New method fs.openFile()

This new method allows reading files outside of the app's sandbox via a native file picker UI. The API allows to specificy the the expect file type, and whether multiple files are allowed or not.

ImageBitmap crop & resize

The createImageBitmap function now accepts parameters to crop and/or resize the given image. The source can be a Blob, ImageData, Canvas or another ImageBitmap object.

Redux Support

Tabris now offers dedicated API for redux based application development. Any widget, custom component or functional component can be connected to a global redux store. Redux store state changes can be mapped to widgets properties, and widget events can be mapped to redux actions.

Widget Factories

Widget constructors may now be called without the new keyword, making them function as factories as well. As as factory they not only take properties (like a constructor), but also event listener and children - like in Tabris-JSX. Unlike JSX no compiler is necessary. Custom components can support this syntax by calling the new asFactory function on the component class.

Better Functional Components

In Tabris 3.6 the already existing general prupose property data becomes settable. This provides all widgets with the possibility to store custom state. Using a change event listener or the creatly improved apply method, functional components can now create create widgets that update themselves whenever the data is propy is set to a new value.

Android

Design Update

The look-and-feel of ActivityIndicator, ProgressBar, Slider, Switch widgets as well as the DateDialog has been updated.

Secure Store support

The secureStore was so far only supported on iOS, but is now also available on Android.

Version 3.5.0

13 May 14:24
Compare
Choose a tag to compare

Developer experience

Improved Error Reporting

The source map support for stack traces broke in 3.4 and has now been fixed. You need to update both the tabris module and the CLI to 3.5 for it to work again. In addition, unhandled errors in setTimeout/setInterval callbacks and rejected promises are now always logged automatically.

CLI "serve" updates

The "-l" (or "--log-requests") CLI switch will now log a summary of all fetch() and XMLHttpRequest in the CLI terminal. The previous behavior of "-l" was to log requests received by the CLI's own http server. This feature is still available by setting an environment variable "TABRIS_CLI_SERVER_LOG=true". This is useful for debugging connection issues during app sideloading.

There is also a new shortcut "CTRL+P" which lets you print out a XML summary of the UI state (previously done via "CTRL+U") OR of the localStorage content.

API

New function "app.share()"

The new share api asks the operating system to share the data with another installed app. The behavior of this API follows the W3C Web Share API. It supports to share text, url and files as well as to provide a title to show in the share dialog.

Support for "font" and "textColor" attributes in markup

In a TextView with markupEnabled set to true all elements (except <br/>) may have "font" and "textColor" attributes. As plain text these accept CSS-like font/color strings. When the text is given as the content of a <TextView> JSX element, both attributes support the usual "ColorValue" and "FontValue" syntax, such as instanced of the "Font" and "Color" classes.

Support for badges on top TabFolder tab bar on Android

The Android platform now allows to show a badge on a top TabFolder bar. iOS continues to only support the bottom location.

Resource management for fonts, colors and texts

A powerful new mechanism is introduced that supports a JSON-based selector syntax to create resource "dictionaries" based on the platform, device language setting or screen scale factor. Currently there is explicit support for fonts, colors and strings, though technically any data type can be used - just without IDE tooling via JSON schema.

A simple JSON data file that provides internationalized texts for your application may look like this:

{
  "$schema": "../node_modules/tabris/schema/texts.json",
  "$fallbackLanguage": "en-US",
  "hello": {
    "en": "Hello World!",
    "de": "Hallo Welt!"
  },
  "pickColor": {
    "en-us": "Pick a color",
    "en-gb": "Pick a colour",
    "de": "Wähle eine Farbe"
  }
}

This is then converted to a flat resource dictionary like this:

import {TextResources} from 'tabris';
import * as textData from './texts.json';
export const texts = TextResources.from(textData);

And used like this:

import {texts} from './resources';
//...
textView.text = texts.hello;

The resulting object is entirely type safe as well (in TypeScript), so there is no need to constantly look up the available keys. In addition this mechanism supports inheritance, cross-references and value conversion.

New decorator "@prop"

With this release @property gained a number of new options, and @prop acts as an alias that enables all of these by default, making it the "smarter" variant. Unlike @property, @prop always requires type information to work properly, which are implicitly provided in TypeScript and explicitly in JavaScript by passing a constructor like this:

@prop(String)
myProp;

Further differences:

  • The properties initial value is not undefined but depends on the type. For example, string properties are initialized with an empty string. The initial value my also be configured explicitly.

  • If set to null or undefined the property is reset to its initial value. If the initial value is also null (which is the default for non-primitives) an exception is thrown.

  • All values will be automatically converted to the expected type (if possible). This adds a layer of error tolerance, especially in JavaScript, but is also useful for for data binding or when creating models from untyped data sources such JSON strings. It's also possible to use a custom converter function.

  • Objects used as property values may implement an "equals" method to indicate whether or not the new value can be considered equal to the current one. If that is the case the new value will be ignored. Similarly, if the property contains an array and is set to another array that is shallow-equal (has the same length and entries), the property will keep the current value.

TypeScript

Tabris.js now officially supports/recommends TypeScript 3.8 (previously 3.3). Older TypeScript version will not be tested.

JavaScript

All JavaScript runtimes in Tabris.js 3.5 support the "async/await" syntax natively without any compiler/transpiler/polyfill. This was actually already the case in 3.4, but overlooked in the release notes.

Version 3.4.0

19 Mar 16:09
Compare
Choose a tag to compare

Developer experience

New developer toolbar

The existing developer console has been replaced by new development tools. The main element is a persistent toolbar akin to a browser URL bar, sitting atop the screen and above the application UI. It provides quick access to essential development utilities. Most importantly it informs you where the application code is loaded from, allows to insert a different URL (also scannable via qr-code on Android), lets you reload the app and open the console logs.

As with the previous developer console, the new developer tools are only available when your app is build with the EnableDeveloperConsole flag. The developer tools can also be explicitly hidden when not required. This can be done via its the developer tools menu entry or by using the new devTools service API.

New and improved debugger support on Android

Tabris.js now supports the V8 inspector protocol on Android platforms. This means you have a fully-featured step-by-step debugger available to use in your favorite IDE. Source maps are applied automatically (when sideloading the code), meaning you'll see your TypeScript or JSX code when debugging and not the JavaScript output.

Project templates updated

When generating a new Tabris.js project via tabris init it can now be pre-configured for debugging via Visual Studio Code. The tslint configuration also has been replaced with similar eslint configurations, complete with TypeScript and JSX support. The questionnaire itself has been trimmed down a bit, with the option to generate Tabris.js 2.x apps no longer being available.

CLI "serve" updates

The serve command has received various improvements:

  • The new --qrcode-renderer option allows to choose a different formatting for the QR code. The default is utf8, but some terminals may not display these characters as expected. In this case setting the option to terminal will produce a larger-but-safer version of the code.
  • The colors and formatting of the printed output has been tweaked for readability.
  • The stability of the debug-connection (handling logging and auto-reload) has been improved significantly.
  • You can now have a variety of key shortcuts available to interact with the running app, such as CTRL+R for reload and CTRL+U for printing a UI tree. It is also possible to backup and restore the localStorage content.

API

Extended file system API

The fs object has some new methods, mostly for handling directories:

  • createDir(path) creates a new directory at the given path
  • removeDir(path) removes an empty directory
  • remove(path) removes any file or directory, empty or not
  • isFile(path) checks if the given path points to a file
  • isDir(path) checks if the given path points to a directory
  • appendToFile(path, data) adds data to a new or existing file

On Android, paths to external storage are made available via the externalFileDirs and externalCacheDirs properties.

Data binding in JavaScript/JSX

The data binding capabilities of Tabris.js rely on the TypeScript compiler (tsc) to transform non-standard syntax and include type information in the compiled code. So far this meant that only .ts and .tsx files could use data binding. This has been changed so that .js and .jsx files are also supported, as long as they are still processed by tsc. Due to the missing type information an "unsafe binding" warning will be logged in certain cases, which can be fixed by adding some type data in code.

In future releases it may be possible to suppress these warnings entirely, as well as using the API entirely without the TypeScript compiler, i.e. in "vanilla" JS.

Version 3.3.0

27 Jan 10:53
Compare
Choose a tag to compare

UI

Widget "Row" and Layout "RowLayout"

These are exact analogues to the existing Stack widget and StackLayout.

The Row widget is a composite that is automatically arranges its children in one horizontal line, like a single-row table. The corrosponding layout manager RowLayout may also be used on Composite, Canvas, Page and Tab via their layout property.

The default vertical layout of each child is controlled by the alignment property which can be set to 'top', 'bottom', 'centerY', 'stretchY' or 'baseline'. Individual child elements can be layouted different from the default via their own layout properties.

A very simple example:

<Row alignment='top' padding={4} spacing={24} >
  <TextView>lorem</TextView>
  <TextView>ipsum dolor</TextView>
  <TextView>sit amet</TextView>
</Row>

A more elaborate example can be found here.

Canvas Method "toBlob"

This new method on the Canvas widget creates a Blob object containing the image drawn on the canvas as a compressed image file. This can be a JPEG, PNG or WebP file. (WebP is only supported on Android).

It's really simple to use:

canvas.toBlob(blob => doSomething(blob), 'image/jpeg');

The resulting image may be written to disk via the fs service or sent to a server via fetch(). It can also be set on any widget property that supports the ImageValue type.

Function "createImageBitmap" supports Canvas instances

The createImageBitmap() method can now create ImageBitmap instances from a Canvas instance. This recommended over canvas.toBlob() if the image is only used as an ImageValue on some widget and no access to the raw data is needed.

Button property "autoCapitalize"

The new property autoCapitalize controls how the button text is capitalized with the following options:

  • 'default' - The platform decides on the capitalization
  • 'none' - The text is displayed unaltered
  • 'all' - Every letter is capitalized

Data Binding

New Components "ListView" and "ItemPicker"

ListView is an extension of CollectionView that adds high-level convinience API suitable for data binding. The ItemPicker does the same for Picker. Both provide an items property that take instance of List, which is provided by the tabris-decorators module. List features a subset of the standard Array interface, but unlike arrays it can be observed. This means any change to the list is immediately applied to the widget. In case of ListView the change is even animated. Scoll position (for ListView) and selection state (for ItemPicker) are preserved if possible.

The items properties also accept arrays, but in that case changes are not tracked. Instead of modifying the array the property needs to be set to a new array instance.

Both widgets also feature new selection API that directly provide the selected item value instead of just a selection index. Callbacks are not needed anymore either, meaning ListView and ItemPicker can now be more conviniently created in JSX. To do so the <ListView> element needs to contain a<Cell> element which is duplicated as often as needed. Multiple <Cell> elements may be given to display different item types.

Example:

      <ListView stretch items={generate(20)}>
        <Cell padding={8} height={52}>
          <TextView centerY template-text='The color of ${item.text}:' font='24px'/>
          <Composite  stretchY left='prev() 24' width={80} bind-background='item.color'/>
        </Cell>
      </ListView>

Services

Event "keyPress"

On app there now is a keyPress event fired when a hardware key is pressed. Note that these events stem from physical hardware, not from the virtual keyboard. The event object provides the keys' character, keycode and various meta data. The events prevendDefault() method can be used to prevent the default action of the key so the application may define it's own behavior.

Service "sizeMeasurement"

This is a service object that can measure the size of a given text in device independent pixel (DIP). Both synchroneous and asynchroneous API is available.

Other

New CLI "serve" options

The tabris serve command has some minor new features:

  • The --external option allows to define an URL as the only availble external address, which will then also be encoded in the QR code.
  • The --port option allows to define the actual port of the HTTP server so it matches the one given via --external.
  • With the --no-intro option the QR code is not printed to the console. However, the QR code is now always available on the HTML site served by the CLI on the default URL with no path. So if the CLI runs on port 8080, entering http://localhost:8080 in a browser will still display the code.

Repository "tabris-decorators" supports GitPod

GitPod is an online IDE that can instantly provide a ready-to-code dev environment for any GitHub repository. Thanks to the CLI updates mentioned above it is now possible to side-load a tabris project in the developer app directly from a running GitPod instance.

The "tabris-decorators" repository has been pre-configured for this use case. Upon opening the repository in GitPod a script will launch that install the tabris CLI and print a list of available examples that can be launched via npm start <example>. It is also possible to directly launch a specific example using a custom URL. For the example labeled-input this would be:

https://gitpod.io/#example=labeled-input/https://github.com/eclipsesource/tabris-decorators/tree/master/examples/labeled-input