
# vd

Expressive syntax for Virtual DOM and CSS.

## How to use

DOM markup:

```js
import dom from 'vd';

let div = dom('div.main',
  dom('p', 'This is a paragraph'),
  dom('<img src="test.png">'),
  dom('footer',
    'Expressive but without ',
    dom('b', 'bloat')
  )
);
```

CSS declarations:

```js
let css = dom.style();
css.add('div > p', {
  'font-weight': 'bold',
  'text-decoration': 'underline'
});
div.add(css);
```

## Features

- Tiny size (3kb gzip+minified)
- Expresiveness and versatility
  - Jade style
    `dom('div.main.left')`
    
  - jQuery style
    `dom('<a href="#">')`
    
  - Attribute objects
    `dom('div', { title: 'Help' })`
    
  - Inline text nodes
    `dom('div', 'Some text')`
    
  - Array children
    `dom('div', [dom('div'), dom('div')])`
    
  - ...children
    `dom('div', dom('div'), dom('div'))`
    
- First-class CSS syntax support
- Node.JS compliance for server rendering

## API

The main module exports the following:

- `vd` (default)
- `style`
- `Node`
- `Text`
- `Element`

### vd(str[, props[, … children]])

The default function that's imported when you run
`require('vd')` allows you to seamlessly create
`Element` objects.

The signature is versatile. The first parameter
is always the tag definition.

The following styles are supported:

- `div`
- `div.class`
- `div.multiple.classes`
- `div title=hello`
- `div title=hello accesskey=k`
- `div title="hello there"`
- `<div title="hello there">`

Optionally, you can specify an attributes key pair as
the second parameter.

```js
dom('img', { src: 'image.jpg' })
```

Two attributes behave especially when using `vd()` to
create an element:

- `class`: if defining classes in the first parameter,
  it _appends_ instead of replacing
  
  ```js
  // <div class="a b">
  dom('div.a', { class: 'b' });
  ```
- `classes`: accepts an object with classes and keys
  that only get added if the value is truthy:
  
  ```js
  // <div class="a b">
  dom('div.a', { classes: { b: true, c: false }) });
  ```

The rest of the parameters can be 0 or more children
elements or text nodes.

Strings and numbers turn into `Text` nodes.

Arrays can be used to specify children. If arrays within
arrays are found, they're flattened. If `null` is found,
it's ignored. That results in extra expressiveness:

```js
dom('div', [
  loggedIn ? dom('<a href="#">', 'Log out') : null,
  friends.map(name => dom('span', name))
]);
```

See below for the `Element` API.

### style()

Initializes a new `Style` element, which inherits from
`Element` but adds convenience methods for 
defining the style content of the element.

The CSS API is provided by [x-css](http://github.com/auotmattic/x-css).

### Element(String tag[, isVoid])

Initializes a new `Element` with the tag `tag`.

If `isVoid` is provided, it's a `Boolean` representing
whether the element is "self-closing" (like `img`).
Otherwise it will be automatically determined based on
a list of known void tags.

Extends `Node`.

### Element.add(Node child[,… Node child2[, …]])

Adds one or more `Node` objects as children. Commonly
`Text` nodes or other `Element` objects.

Any parameter can also be an `Array` of `Node` objects.

Returns itself for chaining.

### Element.set(Object props)

Returns itself for chaining.

### Element.set(String prop, String value)

Sets the property `prop` to `value`.

- If the property is `text`, it appends a new `Text` node as a child.
- If the property is `style` and is an `Object`, it gets
  serialized as CSS and stored.

Returns itself for chaining.

### Element.remove(Node child)

Removes the child node referenced by `child`.

Returns itself for chaining.

### Element.toHTML()

Returns a `String` HTML5 serialization of the `Element` and
its children.

### Element.name

A `String` representing the tag name.

### Element.attrs()

Returns an `Object` of attributes associated
with this element.

### Element.void

a `Boolean` representing if the element is void (self-closing).

### Element.children

An `Array` of nodes.

### Text(String value)

Initiales a new text node with the given `value`.

Extends `Node`.

### Text.value()

Returns the text value of the node.

### Style()

Initializes a new style element that exposes
the expressive [x-css](https://github.com/automattic/x-css)
`Sheet` API.

Extends `Element`.

### Style.add(String sel, Object props)

```js
let css = dom.style();
css.add('div', {
  border: '3px solid red'
});
```

Creates and appends a `Ruleset` for the selector
`sel` and declarations `decs`.

Returns the `Style` element for chaining.

### Style.anim(Object frames)

```js
let fade = css.anim({
  from: { opacity: 0 },
  to: { opacity: 1 }
})
css.add('div', {
  animation: `${fade} 1s ease-in`
});
```

Creates a new `Animation` scope with the given `frames`,
and appends it.

Returns a random animation name as a `String`.

### Sheet.media(String params)

```js
let iphone = css.media('(min-device-width: 768px)');
iphone.add('.menu', {
  display: 'none'
});
```

Creates a new `Media` scope with the given `frames`,
and appends it to the current scope.

Returns the created scope.

### Node()

Basic interface implemented by `Text` and `Element`

## License

MIT
