Ivi Versions Save

Lighweight Embeddable Web UI Library

v0.25.0

5 years ago

Context

New context implementation provides a slightly different API that makes it possible to remove dirty context checking during updates and dirty checking, doesn't require to provide value type when retrieving context values, and doesn't use global namespace for context keys.

BEFORE:

const C = component((c) => {
  const getValue = useSelect((c) => context<{ value: number }>().value);
  return () => getValue();
});

render(
  Context({ value: 123 },
    C(),
  ),
  container,
);

AFTER:

const Value = contextValue<number>();
const C = component((c) => {
  const getValue = useSelect((c) => Value.get());
  return () => getValue();
});

render(
  Value.set(123,
    C(),
  ),
  container,
);

Reconciler

Children reconciliation algorithm for fragments were changed to dynamically add/remove at the end of the fragment instead of reinstantiating entire fragment when fragment length is changed.

v0.24.0

5 years ago

shouldUpdate

All shouldUpdate functions are replaced with their inverse function areEqual.

APIs affected by this change:

  • component(_, shouldUpdate)
  • statelessComponent(_, shouldUpdate)
  • useSelect(_, shouldUpdate)
  • useEffect(_, shouldUpdate)
  • useLayoutEffect(_, shouldUpdate)
  • useMutationEffect(_, shouldUpdate)
  • memo(_, shouldUpdate)
  • selector(_, shouldUpdate)

Tests

New package ivi-jest adds a collection of useful tools for testing with jest library. All ivi tests were completely rewritten using a new ivi-jest library.

Scheduler

ivi-scheduler and ivi-test-scheduler packages were removed. Old unit tests were using package aliasing to mock scheduler behavior and now it is not needed anymore.

Events

Removed optional bubbling, all events are now always bubble.

Bug Fixes

  • Fast path for TrackByKey hasn't been executed correctly when nodes doesn't change their positions. It is hard to test because it is still works correctly even when this fast path doesn't execute.
  • Prevent VALUE() and CONTENT() attribute directives from accepting numbers, they should work only with string values.
  • shouldUpdate functions hasn't been executed correctly in component hooks and caused more updates than it was necessary.

v0.23.0

5 years ago

Synthetic Events

Synthetic event internals were heavily redesigned to reduce overall complexity and improve API flexibility for customsynthetic events.

Custom synthetic events can now inject their own behavior into event flow of native events. It should significantly improve performance when there are many custom synthetic events as it won't be necessary to traverse virtual dom tocollect dispatch targets for each custom synthetic event.

API for creating custom synthetic events is still an unstable API and it is most likely that there will be changes in the future, but it is an extremely useful API that solves alot of problems with UI applications.

Native events are no longer wrapped in a SyntheticNativeEvent object

BEFORE

onClick((ev) => {
  console.log(ev.native.target); // target
});

AFTER:

onClick((ev) => {
  console.log(ev.target);
});

EventFlags is removed

To stop event propagation event handler should return true value.

BEFORE:

onClick((ev) => {
  return EventFlags.PreventDefault | EventFlags.StopPropagation;
});

AFTER:

onClick((ev) => {
  ev.preventDefault();
  return true;
});

currentTarget is now accessible as a second argument

BEFORE

onClick((ev) => {
  console.log(ev.node); // currentTarget
});

AFTER:

onClick((ev, currentTarget) => {
  console.log(currentTarget);
});

SyntheticEvent interface is removed

SyntheticEvent interface had two properties: node and timestamp. node were used to assign current target, it is replaced with an additional argument in all event handler functions. timestamp is a leftover from an old synthetic events implementation that tried to fix cross-browser quirks. For many custom synthetic events this property doesn't have any value and it custom event implementor should decide when timestamp value is necessary.

beforeNativeEvent() and afterNativeEvent() are removed

It is replaced with an addNativeEventMiddleware().

addNativeEventMiddleware(MOUSE_DOWN, (event, next) => {
  // beforeNativeEvent...
  next(event);
  // afterNativeEvent...
});

Portals

Portals were completely redesigned and moved to ivi-portal package. Portals now correctly propagate context through portal entries.

import { _, render, component, invalidate, Events, onClick, } from "ivi";
import { div, button } from "ivi-html";
import { portal } from "ivi-portal";

const MODAL = portal();

const App = component((c) => {
  let showModal = false;
  const showEvent = onClick(() => { showModal = true; invalidate(c); });

  return () => (
    [
      showModal ? MODAL.entry(div("modal", _, "This is being rendered inside the #modal-root div.")) : null,
      Events(showEvent,
        button(_, _, "Show modal"),
      ),
    ]
  );
});

render(App(), document.getElementById("app"));
render(MODAL.root, document.getElementById("modal-root"));

Error Handling

Unhandled exceptions raised inside of a catchError() block are now considered as userspace bugs and will change application state to "error". When application state is "error", all entry points wrapped in catchError() will be blocked to prevent potential security issues because it is impossible to infer which part of an application state caused a bug.

All ivi entry points like render(), synthetic event handlers, etc are wrapped with a catchError() block.

Creating custom functions wrapped with a catchError()

const entryFn = catchError((arg1, arg2) => {
  // ...
});

entryFn(arg1, arg2);

Reconciler

  • Fixed bug when direct child node of a Context() node triggers replace operation.
  • Fixed bug when strictly equal direct child node of an HTML/SVG element doesn't trigger deep dirty checking.
  • Fixed bug when useUnmount() hook hasn't been receiving an undocumented true value as a first argument. It is an unstable feature that can be used for micro optimizations in custom hooks.
  • Added shortcuts for DOM property accesors that should reduce megamorphic call-sites.

Misc

  • Replaced containsRelatedTarget() with a generic function containsDOMElement().
  • Added hasDOMElementChild() function.
  • Removed autofix for Mouse Event bubbling in iOS
  • Added VisitNodesDirective to get a better control over visitNodes() algorithm.
  • Added onTransitionRun() and onTransitionStart() events.

v0.22.0

5 years ago

Added support for events:

  • onBeforeInput()
  • onTransitionCancel()
  • onTransitionEnd()

Breaking Changes

Global Variables replaced with Environment Variables

__IVI_DEBUG__ and __IVI_TARGET__ were replaced with process.env.NODE_ENV !== "production" and process.env.IVI_TARGET to support parcel bundler Issue #10.

v0.21.0

5 years ago
  • Full support for server-side rendering renderToString()
  • Reduced code size

Breaking Changes

Global Variables

DEBUG and TARGET were renamed to __IVI_DEBUG__ and __IVI_TARGET__ to prevent name conflicts with variables that can be used in different packages.

useSelect()

Context argument is removed from selectors, context() function should be used to access current context.

function useSelect<T>(
  c: StateNode,
  selector: (props?: undefined, prev?: T | undefined) => T,
): () => T;
function useSelect<T, P>(
  c: StateNode,
  selector: (props: P, prev?: T | undefined) => T,
  shouldUpdate?: undefined extends P ? undefined : (prev: P, next: P) => boolean,
): undefined extends P ? () => T : (props: P) => T;

Attribute Directives

Attribute directives were changed to support server-side rendering:

interface AttributeDirective<P> {
  v: P;
  u?: (element: Element, key: string, prev: P | undefined, next: P | undefined) => void;
  s?: (key: string, next: P) => void;
}

s() method can be used to alter renderToString() behavior.

VALUE() directive

VALUE() directive now works only with HTMLInputElement elements. New CONTENT() directive should be used to assign value for HTMLTextArea elements.

VALUE() directive emits value="${v}" attribute when rendered to string.

CONTENT() directive emits children string <textarea>${v}</textarea> when rendered to string.

v0.16.0

5 years ago

Bug Fixes

  • events: ignore non-vdom nodes when dispatching events (5904715)

Features

  • package: deprecate unpkg modules (27e8379)
  • test: add support for text content (d1b02ca)
  • vdom: bring back optimization for singular text nodes (b39555d)
  • vdom: clone subtree for prerendered elements (2f9bfb3)

0.15.0

5 years ago

Bug Fixes

  • vdom: add missing exports (4ab29a9)

Features

  • scheduler: add optional argument flags to render() function (6be1314)
  • scheduler: fail early when scheduler hasn't been configured (1eeb3b2)
  • scheduler: improve invalidate functions (8f5a328)
  • scheduler: make default invalidate handler NOOP (ec6a479)
  • scheduler: remove obsolete function isHidden() (23ab024)
  • state: simplify store implementation (79c31a2)
  • vdom: add support for removing events in EVENT() (437e4ce)
  • vdom: add syncable value AUTOFOCUS() (18460e7)
  • vdom: add syncable value EVENT() (2546f8e)
  • vdom: move text node factory t() from html package to ivi (d53d8e9)
  • vdom: remove direct dependency with a complex scheduler (34807fd)

0.14.0

6 years ago

Bug Fixes

  • events: fix incorrect imports ivi-events => events (368c387)
  • gestures: fixes browser quirk with TouchMove events (9fedf9e)
  • test: fix rendering attrs to snapshot (syncable values) (9f1de27)
  • types: support number types for css property "bottom" (4ff9486)
  • vdom: remove obsoleted checks in DEBUG mode (4274d57)

Code Refactoring

  • vdom: rename newPropsReceived() to propsChanged() (6434f5a)

Features

  • core: add underscore _ as an alias to undefined (35834f4)
  • debug: add DEBUG pubsub to expose internal state (466aba2)
  • gestures: add multitouch transform gesture recognizer (28991fe)
  • gestures: change gesture recognizers lifecycle (af2b86a)
  • gestures: fix bugs, add more gesture recognizers (a63b27f)
  • gestures: fully working gesture events prototype (b310dcf)
  • scheduler: add beforeUpdate / afterUpdate repeatable tasks (f599405)
  • scheduler: remove frame task queue after (d3c4f72)
  • scheduler: remove visibility observers (d816fda)
  • types: add types for specialized properties in attribute lists (69cc9a2)
  • vdom: add mapIterable() to support iterable objects (c09c5cb)
  • improve dev mode checks (4e7db28)
  • vdom: add universal syncable value PROPERTY() (111c309)
  • vdom: don't trigger updated() for all parents (5c75401)
  • vdom: new attribute syncing algorithm (564957d)
  • vdom: remove support for null nodes returned from mapIterable() (e3c88a5)
  • vdom: rename instance getters (bbcf255)
  • vdom: replace VNode methods a() and s() with factory args (4f00a52)
  • remove factories for obsolete elements, improve types for attrs (c2b9173)
  • rename INPUT_VALUE() and INPUT_CHECKED() to VALUE() and CHECKED() (943a414)

Performance Improvements

  • events: improve event dispatcher algorithm (352287a)

BREAKING CHANGES

  • vdom: getDOMInstanceFromVNode() and getComponentInstanceFromVNode() were renamed to getDOMNode() and getComponent()
  • vdom: VNode methods value() and unsafeHTML() were removed.

Before:

input("", { type: "checked" }).value(true);
use("", { "xlink:href": "sprite.svg#a" });
div().unsafeHTML("abc");

After:

input("", { type: "checked", checked: CHECKED(true) });
use("", { "xlink:href": XLINK_ATTR("sprite.svg#a") });
div("", { unsafeHTML: UNSAFE_HTML("abc") });
  • scheduler: currentFrameAfter() and nextFrameAfter() functions were removed.
  • scheduler: DOM reader and animation tasks were replaced with beforeUpdate() and afterUpdate() task lists.
  • vdom: Component lifecycle method newPropsReceived() renamed to propsChanged().
  • vdom: VNode methods a() and s() were replaced with optional arguments for all element factory functions.

Before:

div("className").a({ id: "ID" }).s({ color: "red" });

After:

div("className", { id: "ID" }, { color: "red" });
  • vdom: updated() lifecycle is now triggered only for components that were updated. Parent components won't be receiving any information that their children were updated.

Initially it was implemented to solve use cases with jumping scroll positions when children layout is modified. But there is a better way, scheduler allows to register repeatable tasks that will be invoked before any rendering to read from the DOM, and after all rendering is done, this hooks solve this use case perfectly. And since I don't know about any use cases that would require such behavior, it would be better to reduce API surface. All major frameworks doesn't support such behavior.

0.13.0

6 years ago

Bug Fixes

  • events: use correct options for active events (c25e3eb)

Features

  • events: add checks in DEBUG mode when removing event listeners (a28cde2)
  • events: completely redesigned synthetic events (a0ad90d)

BREAKING CHANGES

  • events: ivi-events package were removed, event handler factories should be imported from ivi package.

0.12.0

6 years ago

Code Refactoring

  • events: remove methods from synthetic events (e6d3f1e)

Features

  • events: check returned event flags in DEBUG mode (2fc17db)

Performance Improvements

  • gestures: optimize velocity tracker (aeba6bd)

BREAKING CHANGES

  • events: Synthetic event methods preventDefault() and stopPropagation() were removed.

Before:

onClick((ev) => {
  ev.preventDefault();
  ev.stopPropagation();
});

After:

onClick(() => EventFlags.PreventDefault | EventFlags.StopPropagation);