cyclejs/cycle-core

View on GitHub
docs/api/dom.html

Summary

Maintainability
Test Coverage
<!doctype html>
<html>

<head>
  <meta charset='utf-8'>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width">
  <title>Cycle.js - API reference (dom)</title>

  <!-- Flatdoc -->
  <script src='../support/vendor/jquery.js'></script>
  <script src='../support/vendor/highlight.pack.js'></script>
  <script src='../legacy.js'></script>
  <script src='../flatdoc.js'></script>

  <!-- Algolia's DocSearch main theme -->
  <link href='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css' rel='stylesheet' />

  <!-- Others -->
  <script async src="//static.jsbin.com/js/embed.js"></script>

  <!-- Flatdoc theme -->
  <link href='../theme/style.css' rel='stylesheet'>
  <script src='../theme/script.js'></script>
  <link href='../support/vendor/highlight-github-gist.css' rel='stylesheet'>

  <!-- Meta -->
  <meta content="Cycle.js - API reference (dom)" property="og:title">
  <meta content="A functional and reactive JavaScript framework for predictable code" name="description">

  <!-- Content -->
  <script id="markdown" type="text/markdown" src="index.html">
# Cycle DOM - [source](https://github.com/cyclejs/cyclejs/tree/master/dom)

A Cycle.js driver to enable interaction with the DOM. The driver is based on [snabbdom](https://github.com/paldepind/snabbdom/) as the Virtual DOM library.

```
npm install @cycle/dom
```

## Browser support

These are the browsers we officially test for:

- Chrome 49 and higher
- Firefox 52 and higher
- Safari 9.1 and higher
- Android Chrome (OS version 4.4 and higher)
- iOS Safari (OS version 10.3 and higher)
- Microsoft Edge
- Internet Explorer 11

**Note for Internet Explorer 10:** This driver works on IE10 only if you polyfill ES6 Map, ES6 Set, [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) (we recommend `mutation-observer` package from npm) **and** if you don't render the app in a [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment).

In other browsers, the DOM driver may not work or may work partially.

# Isolation semantics

Cycle DOM supports isolation between components using the `@cycle/isolate` package. Here is how isolation contexts work in Cycle DOM given a `scope` to `isolate(Component, scope)`:

**When the scope is the `':root'` string: no isolation.**

The child component will have run in the same context as its parent, and methods like `DOMSource.select()` will inspect the DOM trees of the parent. This means the child component is able to inspect DOM trees that it did not itself produce.

**When the scope is a selector string (e.g. '.foo' or '#foo'): siblings isolation.**

A `DOMSource.select()` call in a parent component will have access to the DOM trees in both children isolated with "siblings isolation" (which means there is no parent-child isolation). However, a `DOMSource.select()` inside a child component isolated with "siblings isolation" will have no access to the DOM trees in other children components isolated with "siblings isolation".

**When the scope is any other string: total isolation.**

A `DOMSource.select()` call in a parent component will have no access to the DOM trees in a totally isolated child. Also, sibling components will have no access to the DOM trees in a totally isolated sibling component.

# API


## <a id="makeDOMDriver"></a> `makeDOMDriver(container, options)`

A factory for the DOM driver function.

Takes a `container` to define the target on the existing DOM which this
driver will operate on, and an `options` object as the second argument. The
input to this driver is a stream of virtual DOM objects, or in other words,
Snabbdom "VNode" objects. The output of this driver is a "DOMSource": a
collection of Observables queried with the methods `select()` and `events()`.

**`DOMSource.select(selector)`** returns a new DOMSource with scope
restricted to the element(s) that matches the CSS `selector` given. To select
the page's `document`, use `.select('document')`. To select the container
element for this app, use `.select(':root')`.

**`DOMSource.events(eventType, options)`** returns a stream of events of
`eventType` happening on the elements that match the current DOMSource. The
event object contains the `ownerTarget` property that behaves exactly like
`currentTarget`. The reason for this is that some browsers doesn't allow
`currentTarget` property to be mutated, hence a new property is created. The
returned stream is an *xstream* Stream if you use `@cycle/xstream-run` to run
your app with this driver, or it is an RxJS Observable if you use
`@cycle/rxjs-run`, and so forth.

**options for DOMSource.events**

The `options` parameter on `DOMSource.events(eventType, options)` is an
(optional) object with two optional fields: `useCapture` and
`preventDefault`.

`useCapture` is by default `false`, except it is `true` for event types that
do not bubble. Read more here
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
about the `useCapture` and its purpose.

`preventDefault` is by default `false`, and indicates to the driver whether
`event.preventDefault()` should be invoked. This option can be configured in
three ways:

- `{preventDefault: boolean}` to invoke preventDefault if `true`, and not
invoke otherwise.
- `{preventDefault: (ev: Event) => boolean}` for conditional invocation.
- `{preventDefault: NestedObject}` uses an object to be recursively compared
to the `Event` object. `preventDefault` is invoked when all properties on the
nested object match with the properties on the event object.

Here are some examples:
```typescript
// always prevent default
DOMSource.select('input').events('keydown', {
  preventDefault: true
})

// prevent default only when `ENTER` is pressed
DOMSource.select('input').events('keydown', {
  preventDefault: e => e.keyCode === 13
})

// prevent defualt when `ENTER` is pressed AND target.value is 'HELLO'
DOMSource.select('input').events('keydown', {
  preventDefault: { keyCode: 13, ownerTarget: { value: 'HELLO' } }
});
```

**`DOMSource.elements()`** returns a stream of arrays containing the DOM
elements that match the selectors in the DOMSource (e.g. from previous
`select(x)` calls).

**`DOMSource.element()`** returns a stream of DOM elements. Notice that this
is the singular version of `.elements()`, so the stream will emit an element,
not an array. If there is no element that matches the selected DOMSource,
then the returned stream will not emit anything.

#### Arguments:

- `container: String|HTMLElement` the DOM selector for the element (or the element itself) to contain the rendering of the VTrees.
- `options: DOMDriverOptions` an object with two optional properties: 
  - `modules: array` overrides `@cycle/dom`'s default Snabbdom modules as
    as defined in [`src/modules.ts`](./src/modules.ts).
  - `reportSnabbdomError: (err: any) => void` overrides the default error reporter function.

#### Returns:

*(Function)* the DOM driver function. The function expects a stream of VNode as input, and outputs the DOMSource object.

## <a id="mockDOMSource"></a> `mockDOMSource(mockConfig)`

A factory function to create mocked DOMSource objects, for testing purposes.

Takes a `mockConfig` object as argument, and returns
a DOMSource that can be given to any Cycle.js app that expects a DOMSource in
the sources, for testing.

The `mockConfig` parameter is an object specifying selectors, eventTypes and
their streams. Example:

```js
const domSource = mockDOMSource({
  '.foo': {
    'click': xs.of({target: {}}),
    'mouseover': xs.of({target: {}}),
  },
  '.bar': {
    'scroll': xs.of({target: {}}),
    elements: xs.of({tagName: 'div'}),
  }
});

// Usage
const click$ = domSource.select('.foo').events('click');
const element$ = domSource.select('.bar').elements();
```

The mocked DOM Source supports isolation. It has the functions `isolateSink`
and `isolateSource` attached to it, and performs simple isolation using
classNames. *isolateSink* with scope `foo` will append the class `___foo` to
the stream of virtual DOM nodes, and *isolateSource* with scope `foo` will
perform a conventional `mockedDOMSource.select('.__foo')` call.

#### Arguments:

- `mockConfig: Object` an object where keys are selector strings and values are objects. Those nested objects have `eventType` strings as keys
and values are streams you created.

#### Returns:

*(Object)* fake DOM source object, with an API containing `select()` and `events()` and `elements()` which can be used just like the DOM Driver's
DOMSource.

## <a id="h"></a> `h()`

The hyperscript function `h()` is a function to create virtual DOM objects,
also known as VNodes. Call

```js
h('div.myClass', {style: {color: 'red'}}, [])
```

to create a VNode that represents a `DIV` element with className `myClass`,
styled with red color, and no children because the `[]` array was passed. The
API is `h(tagOrSelector, optionalData, optionalChildrenOrText)`.

However, usually you should use "hyperscript helpers", which are shortcut
functions based on hyperscript. There is one hyperscript helper function for
each DOM tagName, such as `h1()`, `h2()`, `div()`, `span()`, `label()`,
`input()`. For instance, the previous example could have been written
as:

```js
div('.myClass', {style: {color: 'red'}}, [])
```

There are also SVG helper functions, which apply the appropriate SVG
namespace to the resulting elements. `svg()` function creates the top-most
SVG element, and `svg.g`, `svg.polygon`, `svg.circle`, `svg.path` are for
SVG-specific child elements. Example:

```js
svg({attrs: {width: 150, height: 150}}, [
  svg.polygon({
    attrs: {
      class: 'triangle',
      points: '20 0 20 150 150 20'
    }
  })
])
```


  </script>

  <!-- Initializer -->
  <script>
    Flatdoc.run({
      fetcher: function (callback) {
        callback(null, document.getElementById('markdown').innerHTML);
      },
      highlight: function (code, value) {
        return hljs.highlight(value, code).value;
      },
    });
  </script>

</head>

<body role='flatdoc' class="no-literate">

  

  <div class='header'>
    <div class='left'>
      <h1><a href="/"><img class="logo" src="../img/cyclejs_logo.svg">Cycle.js</a></h1>
      <ul>
        <li><a href='../getting-started.html'>Guide</a></li>
        <li><a href='../api/index.html'>API</a></li>
        <li><a href='../releases.html'>Releases</a></li>
        <li><a href='https://github.com/cyclejs/cyclejs'>GitHub</a></li>
      </ul>
      <input id="docsearch" />
    </div>
    <div class='right'>
      <!-- GitHub buttons: see https://ghbtns.com -->
      <iframe src="https://ghbtns.com/github-btn.html?user=cyclejs&amp;repo=cyclejs&amp;type=watch&amp;count=true"
        allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
    </div>
  </div>

  <div class='content-root'>
    <div class='menubar'>
      <div class='menu section'>
        
        <div role='flatdoc-menu'></div>
        
      </div>
    </div>
    <div role='flatdoc-content' class='content'></div>
    
  </div>
  

  <script>
    ((window.gitter = {}).chat = {}).options = {
      room: 'cyclejs/cyclejs'
    };
  </script>
  <script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
  <script src='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js'></script>
  <script src='../docsearch.js'></script>
</body>

</html>