tabris-js

Create native mobile apps in JavaScript or TypeScript.

BSD-3-CLAUSE License

Downloads
215.9K
Stars
1.4K
Committers
25

Bot releases are visible (Hide)

tabris-js - Version 3.9.0 Latest Release

Published by tbuschto almost 2 years ago

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.

tabris-js - Version 3.8.0

Published by tbuschto about 3 years ago

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.

tabris-js - Version 3.7.1

Published by tbuschto almost 4 years ago

Fixed some memory leaks

tabris-js - Version 3.7.0

Published by tbuschto almost 4 years ago

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.

tabris-js - Version 3.6.1

Published by tbuschto about 4 years ago

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.

tabris-js - Version 3.6.0

Published by tbuschto about 4 years ago

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.

tabris-js - Version 3.5.0

Published by tbuschto over 4 years ago

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.

tabris-js - Version 3.4.0

Published by tbuschto over 4 years ago

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.

tabris-js - Version 3.3.0

Published by tbuschto over 4 years ago

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

tabris-js - Version 2.9.0

Published by tbuschto about 5 years ago

iOS 13 Compatibility

Fixed crash on startup when running on iOS 13

Backports

The following properties have been backported from the 3.x branch:

TextInput: "keyboardAppearanceMode"
app: "idleTimeoutEnabled"

tabris-js - Version 3.2.1

Published by tbuschto about 5 years ago

This patch release fixes compatibility with cordova plug-ins and a bug in the image scaling logic on Android.

tabris-js - Version 3.2.0

Published by tbuschto about 5 years ago

UI

New Widget "CameraView"

Tabris.js 3.2 adds the ability to take images via the devices camera. In order to so so, the tabris.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 asynchrenous 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:

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...
}

Blob and BitmapImage as Generic Images

A compressed image (jpeg, png) obtained as a Blob object - for example via fetch or Camera - can now used anywhere the existing API accepts an ImageValue.

Minimal Example:

  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 the image is already in memory and its size already known before it is used in the UI.

This feature will become much more powerful when the BitmapImage API is extended 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 onscreen keyboard from popping up when a TextInput is focused, or only when it is focused by touch.

Option to control CollectionView.reveal() animation

Previously it was not possible to control whether a CollectionView.reveal() operation would be executed in an animated fashion or not. Now there is parameter a parameter which allows to control this behavior. The default is to animate the reveal operation.

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. Previously this was only possible in a very limited manner. This feature was added to properly support the MVVM (Model-View-ViewModel) programming pattern.

Any instance of a class using the @property decorator on its properties can be used for bindings. One-way bindings to such an object are declared via JSX. The syntax for this remains unchanged, except that it is now also possible to bind to deeply nested properties:

@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. Should the widget properties change for some other reason the source properties keep their value.

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):

@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 TextInut and Slieder properties and vice versa. Of course, if the widget property can't change by itself (i.e. TextInput's message instead of text) this is effectively a one-way binding.

Other

CLI

The tabris init command can now also create projects with MVVM example code, including unit tests.

New Event Handling Method "triggerAsync"

This method is an asynchronous alternative to trigger(). When called with await it pauses for all listener to resolve, including those marked async. This can be desirable - for example - to propagate errors from async listeners to the code that triggers the event, or when writing unit tests that need to verify the behavior of asynchronous code.

Internal Change: Property System Reworked

The internal property system has been partially re-written, which may cause minor differences in behavior. Most notably, properties should now behave more consistently regarding value checking and conversion/normalization. Also, properties that take objects/arrays no longer operate with safe copies. Instead they now keep the exact instance that was set (if no conversion is necessary), but makes them immutable if appropriate.

Due to this change Tabris Plug-Ins targeting 3.0 or 3.1 do not work with 3.2. New compatible versions have been released for the following plug-ins:

  • tabris-plugin-maps (6.0.0)
  • tabris-plugin-firebase (4.0.0)
  • tabris-plugin-barcode-scanner (3.0.0)

Documentation Update

The documentation has been slightly revised, most noteably featuring a more structured table of contents in the left sidebar. Also, the presentation of type information in API documents has been tweaked and now always links to the type in question, either within the Tabris.js documentation or to MDN.

tabris-js - Version 2.8.1

Published by tbuschto about 5 years ago

tabris-js - Version 3.1.0

Published by tbuschto about 5 years ago

New Permissions API

In order the access features like the devices location or camera, the user has to grant corresponding permissions to the app. Tabris 3.1 introduces the permission object that allows the app to check and request these permissions at runtime.

FormData support

Tabris.js now provides the FormData class (including related classes Blob and File) as it is specified by the W3C. It can be used in conjunction with fetch() or XMLHttpRequest to upload data in the "multipart/form-data" encoding.

Widgets API

New CanvasContext method "drawImage"

Until now the CanvasContext class implemented by Tabris.js lacked the W3C standard method drawImage. It has now been added with support for instances of the ImageBitmap class, which represent uncompressed in-memory images. ImageBitmap objects are created with the asynchronous createImageBitmap method using a Blob (containing a .jpg or .png image), ImageData or another ImageBitmap instance as the source.

New property "imageTintColor" on Button

This new property allows to tint the image displayed on a Button widget.

New property "scrollbarVisible" on CollectionView

The property works in the same fashion as scrollbarVisible on the ScrollView by showing or hiding the scroll bar.

New property "maxChars" on TextInput

Allows to limit the maximum number of characters that the user can enter into a TextInput.

New events "select" and "reselect" on Tab

The new "select" event on the Tab fires in tandem with the "select" event on the parent TabFolder, while "reselect" on the Tab fires when the tab is tapped by the user while it is already visible.

Infinite Animations

The animate method now allows Infinity as a value for the repeat option.

tabris-js - Version 2.8.0

Published by tbuschto about 5 years ago

This relase adds some features introduced in Tabris.js 3.0 and 3.1 to Tabris.js 2.x. Like usual it also includes some minor bugfixes.

ImageBitmap and drawImage

Until now the ConvasContext class implemented by Tabris.js completely lacked the w3c standard method drawImage. The new drawImage method takes instances of ImageBitmap, which represent uncrompressed in-memory images. ImageBitmap objects can be created with the asynchronous createImageBitmap method from a Blob contining a JPEG or PNG image.

ImageBitmap is a W3C standard and supported by all three Tabris.js 2 platforms.

Widget property "absoluteBounds"

The new property absoluteBounds provides widget bounds relative to the tabris.ui.contentView widget instead of the direct parent like bounds does.

ScrollView properties "scrollXState" and "scrollYState"

The ScrollView adds the properties scrollXState and scrollYState which indicate whether the view is currently, dragging, scrolling or in a resting position. Matching change events are available to observe these state changes while in motion.

tabris-js - Version 3.0.1

Published by tbuschto over 5 years ago

tabris-js - Version 3.0.0

Published by tbuschto over 5 years ago

tabris-js - 3.0.0-rc1

Published by tbuschto over 5 years ago

General

App

The new read-only property debugBuild can be queried to find out if the app is build in debug mode or release mode as given by the Tabris.js CLI to the tabris build command.

UI

CollectionView

The CollectionView no longer provides a select event as it worked unreliable across platforms. Interactions with a cell have to be handled directly by listeners attached to the cell. The new method itemIndex(cell) may be used to determine the index associated with a cell:

collectionView.createCell = () => {
  const cell = new SomeWidget();
  cell.onTap(() => {
    const index = cell.parent(CollectionView).itemIndex(cell);
    // do something with the item...
  });
  return cell;
}

The method cellByItemIndex(index) was added to allow the reverse - getting the cell widget currently associated with the given index. Can be null when the cell at the given index is currently not displayed.

TextInput

On Android the TextInput appearance can now be customized via the new properties style, and floatMessage. The new properties allow to support the design style guide outlined in the material design specs.

Picker

The Picker now allows to show an empty state. This unselected state can be filled with a new message text property similar to a TextInput. The empty state has the selectionIndex of -1. Setting the selectionIndex to -1 reverts to the empty state and shows the message if available.

On Android the Picker can now be customized via the new properties style, and floatMessage similarly to the new properties introduced on TextInput.

With the introduction of the new style property on Picker, the iOS only property fillColor became redundant and was removed. Previously the fillColor was required to separate the Android underline colorization from the ios picker background color. Setting the Picker style to underline on Android now ignores the background and only applies the borderColor property.

In addition the font property (previously available on Widget in Tabris.js 2.x) has now been added on the Picker explicitly. It changed the appearance of the text shown in the Picker box.

ScrollView

The ScrollView adds the properties scrollXState and scrollYState which indicate whether the view is currently, dragging, scrolling or in a resting position. Matching change events are available to observe these state changes while in motion.

StackLayout and StackComposite

The StackComposite widget introduced in 3.0.0-beta2 was renamed to just Stack and now respects the layoutData of its children. Details can be found in the revised Layout documentation.

TabFolder

The TabFolder has a new property selectionIndex to set the active Tab without having an instance of it. This is especially useful when using JSX where the Tab children are created declaratively and no instance is immediately available.

The badge and badgeColor property are now also supported on Android. The expected type of the badge is now a number instead of a string.

Widget

The padding property is now available on all widgets, not just Composite. It also supports shorthand syntax like [1, 10, 4, 8], '1 10 4 8' or simply 16, in place of {top: 1, right: 10, bottom: 4, left: 8}.

The layoutData preset "fill" was renamed "stretch" and presets "stretchX" and "stretchY" have been added.

A new property excludeFromLayout was added that can be set to true to make the widget not just invisible (like visible = false) but to also make the layout behave as though the widget does not exist. That way there is no empty space where the widget would have been displayed.

The new property absoluteBounds provides widget bounds relative to the tabris.contentView instead of the direct parent like bounds does.

tabris.ui

The tabris.ui object which was already deprecated is now completely removed.

TextView

The TextView alignment value 'center' was renamed to 'centerX'.

AlertDialog

The AlertDialog property texts has been replaced with a ContentView object. Any TextInput instances are appended to it. The ContentViews layout can not be changed and it will position to TextInput objects from top to bottom, similar to replaced texts property.

NavigationView and Actions

Removed properties placementPriority from Action and navigationAction from NavigationView: These properties are replaced by a new property placement on the Action widget. It accepts the values 'default' (same as placementPriority = 'normal'), 'overflow' (same as a placementPriority = 'low') and 'navigation', which puts the action in the place usually reserved by the drawer icon.

Selector API

Introduced global function $() as an alias for tabris.contentView.find(). This especially makes small snippets more readable.

On WidgetCollection the new only() method works like first(), but throws if there is more than one match. It's therefore more secure than first() when selecting a single widget.

The parent() method now also takes a selector, returning the nearest parent that matches.

Removed method find() due to its ambiguous nature. This does not affect composite.find() which still exists.

JSX Stateless Functional Components (i.e. factories) can now be used as selectors, just like widget constructors can.

JSX

All popups now support JSX, i.e. Popover, DateDialog and TimeDialog, in addition to the already supported AlertDialog.

Markup elements: JSX elements can now directly contain tags like <b> and <i>.

Element <$>: This is a globally available element that may be used to group widgets (instead of <WidgetCollection>). It can also contain text, in which case it returns a string.

Almost all layout properties (e.g. left, top, centerY...) now accept true as an alias (usually for 0) which allows a shorter syntax in JSX, e.g. <TextView centerY> instead of <TextView centerY={0}>.

All layoutData preset values ('center', 'stretch', 'centerX', 'stretchY') can now be used as JSX shorthands, e.g. <TextView stretchY> instead of <TextView layoutData='stretchY'>.

TypeScript

Widgets TabFolder, NavigationView and CollectionView are now generic, allowing to narrow down the type of accepted children. The feature already existed on Composite.

The pseudo-property "jsxProperties" that is used to define which JSX attributes are supported in .tsx files was renamed to "jsxAttributes". However, due to changes in the type declaration files of tabris this property should rarely be needed anyway.

Developer Experience

Most Developers Guide articles have been re-written for clarity, links fixed, code examples and images added.

Various internal/low-level APIs have been documented for better extendability/hackability.

The tabris module now includes a sub-module 'ClientMock' that can be used to initialize the tabris module outside of a native Tabris environment, e.g. in node. When generating a new (compiled) Tabris 3.x project via the Tabris CLI (or the yeoman generator) the option to generate such a test setup based on mocha is given. This feature is not yet documented in the developers guide.

The global $() method can be used in the developer console (or CLI with interactive mode) to access any widget (or NativeObject) via its cid number. The cid is usually given in log messages/warning.

tabris-js - 3.0.0-beta2

Published by tbuschto over 5 years ago

UI

StackLayout and StackComposite

The new StackComposite widget arranges all of its children automatically in one vertical stack, starting from the top. Children may be aligned to the left, right, horizontal center, or stretched. The layoutData on the children is currently ignored, but will be supported in the final 3.0 release.

Example:

contentView.append(
  <StackComposite layoutData='fill' spacing={24} >
    <TextView background='red'>lorem</TextView>
    <TextView background='green'>ipsum dolor</TextView>
    <TextView background='blue'>sit amet</TextView>
  </StackComposite>
);

This behavior can be added to most widget that inherit from Composite (e.g. Page, ScrollView) by setting the new layout property to a StackLayout instance.

Example:

contentView.append(
  <ScrollView layoutData='fill' layout={new StackLayout({alignment: 'stretchX'})} >
    <TextView background='red'>lorem</TextView>
    <TextView background='green'>ipsum dolor</TextView>
    <TextView background='blue'>sit amet</TextView>
  </ScrollView>
);

LayoutData Shorthands

In practice widgets often are made to fill their parent completely, or centered on both axes. That behavior can now be achieved with less code by setting layoutData to 'fill' or 'center' instead of an LayoutData object.

Button Styling

The look-and-feel of the Button widget can now be adjusted by setting the style property to "default", "elevate", "flat", "outline" or "text". The default style will create a platform specific appearance.

Logging

Better Stack Traces

Stack traces have been improved in a number of ways:

  • Clean platform-independent format
  • Framework internals are filtered out
  • Source map support, i.e. corrent line numbers when using TypeScript/JSX. (*)
  • cross timer/promise traces - works great in combination with async/ await

(*) Requires the tabris-cli version matching this release, install with npm i [email protected] -g.

The improved stack traces are printed when calling console.trace() or error.toString().

Better warnings

Warnings printed by the framework do now generally include the source objects type and id, and also the file/line number in the application that caused the warning. The phrasing of many warnings has also been revised to be clearer and contain more relevant information.

Improved console.dirxml()

The dirxml method was already introduced in beta 1 as a convenient way to print the applications widget tree (or parts of it), but it only displayed the widget type and id. Now it also prints essential information like widget bounds, selection status, text value, etc.

In addition, dirxml can now also be called with localStorage to inspects its content.

localStorage

The localStorage now also implements key and length as specified in the W3C standard. This allows programmatically inspecting its content without knowing the keys associated with the contained items.

JSX and TypeScript improvements

New object literals for property types

Various properties in Tabris.js used to accept only CSS-like strings, which are short but error-prone. Since the IDE and TypeScript compiler can not know what format a string is supposed to have, no auto-complete could be provided. As a result typos would not become obvious until the code was executed.

The new object literals for font, color and gradient types have full auto-completion and TypeScript support while staying 100% compatible with the old string formats. While layoutData was already an object literal, it now allows objects to express the constraint values, e.g. left and top.

Each type also has a matching JavaScript class that is used as the default format by the framework. For example:

widget.background = {red: 255, green: 0, blue: 0};
// or
widget.background = '#ff0000';
// are normalized to a `Color` instance, i.e.
console.log(widget.background instance Color); // true
console.log(widget.background.toString());  // #ff0000
console.log(widget.background.red);  //255

JSX support for AlertDialog

As with ActionSheet in beta 1, AlertDialog can now be written as JSX. That allows for more readable code when a the dialog contains TextInput elements:

const dialog = AlertDialog.open(
  <AlertDialog title='Sign-in required' buttons={{ok: 'Sign-in', cancel: 'Cancel'}}>
    Provide sign-in credentials to access your personalized content.
    <TextInput message='Username' />
    <TextInput type='password' message='Password' />
  </AlertDialog>
);
const {texts, button} = await dialog.onClose.promise();

The new static open method that serves as a convenient shorthand to create a very simple message dialog:

await AlertDialog.open('Comment saved').onClose.promise();
textView.text = 'Dialog closed';

Documentation

API documentation has been tweaked to improve readability and provide a short, informative overview for each class, method and property at first glance.

Breaking changes

Object 'ui' removed

The 'ui' object used to be a pseudo-widget that contained the main ContentView, the Drawer instance and various pseudo-widgets like StatusBar. This proved to be confusing and sometimes inconvenient, so all objects held by ui are now available as direct imports from the tabris module:

Old:

import {ui, TextView} from 'tabris';
ui.contentView.append(new TextView());

New:

import {contentView, TextView} from 'tabris';
contentView.append(new TextView());

Removed 'installPatch' method

The method app.installPatch allowed to patch a Tabris.js application on the fly without installing a complete new version. This API was always marked as experimental and is now removed again. It encouraged a risky practice (bypassing store policies) and was never widely used.

As a replacement the app.reload method now takes an URL parameter, allowing to execute any local or remote JavaScript in place of the packaged code. This, combined with fetch and the fs file system API would theoretically allow implementing this feature in-app, if desired.

Property 'backgroundImage' merged in to background

The property background was already supporting both colors and gradients, so it was an obvious move to make it accept images as well, eliminating the need for a separate backgroundImage property.