Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/herp-inc/snabbdom-jsx

Yet another JSX pragma for Snabbdom
https://github.com/herp-inc/snabbdom-jsx

jsx snabbdom

Last synced: about 1 month ago
JSON representation

Yet another JSX pragma for Snabbdom

Awesome Lists containing this project

README

        

# @herp-inc/snabbdom-jsx [![npm](https://img.shields.io/npm/v/@herp-inc/snabbdom-jsx)](https://www.npmjs.com/package/@herp-inc/snabbdom-jsx)

Yet another [JSX](https://facebook.github.io/jsx/) pragma for [Snabbdom](https://www.npmjs.com/package/snabbdom)

## Features

- Straightforward and intuitive syntax
- `` rather than ``
- Typechecked attributes on intrinsic elements
- Only for HTML elements for now
- Typechecked children
- `className` and `id` will be the part of the [`sel`](https://github.com/snabbdom/snabbdom#sel--string)
- [Type-safe custom modules via module augmentation](#custom-modules)
- Support for [React 17 style automatic runtime](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)

## Example

```tsx
const vnode = (


This is bold and this is just normal text
I'll take you places!

);
```

## Installation

Note that the following packages are peer dependencies of this library, which need to be installed separately.

| Package | Version |
| ---------------------------------------------------- | ------- |
| [`csstype`](https://www.npmjs.com/package/csstype) | `3` |
| [`snabbdom`](https://www.npmjs.com/package/snabbdom) | `3` |

### With [npm](https://www.npmjs.com/)

```sh
$ npm install @herp-inc/snabbdom-jsx
```

### With [yarn](https://yarnpkg.com/)

```sh
$ yarn add @herp-inc/snabbdom-jsx
```

## Usage

Note that fragments are still experimental. Make sure you are using Snabbdom v3.2+ and opt it in to enable the feature.

```ts
const patch = init(modules, undefined, {
experimental: {
fragments: true,
},
});
```

### With [TypeScript](https://www.typescriptlang.org/)

Add the following options to your `tsconfig.json`:

```json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@herp-inc/snabbdom-jsx"
}
}
```

### With [Babel](https://babeljs.io/)

Add [`@babel/plugin-transform-react-jsx`](https://www.npmjs.com/package/@babel/plugin-transform-react-jsx) to your `devDependencies`.

Add the following options to your Babel configuration:

```json
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"importSource": "@herp-inc/snabbdom-jsx",
"runtime": "automatic"
}
]
]
}
```

## Attributes mapping

By default, an attribute will be passed to [the props module](https://github.com/snabbdom/snabbdom#the-props-module).

```tsx

// { props: { type: 'text' } }
```

However, certain attributes will be treated differently.

### `className` and `id`

`className` and `id` attributes will be concatenated to the [`sel`](https://github.com/snabbdom/snabbdom#sel--string) with `.` and `#` respectively, and won't be passed to any modules. For example, the expression `

` will yield a virtual node with `{ sel: 'div#foo.bar.baz' }`

### `aria-*`

An attribute starting with `aria-` will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).

```tsx

// { attrs: { 'aria-label': 'Send' } }
```

### `data-*`

An attribute starting with `data-` will be passed to [the dataset module](https://github.com/snabbdom/snabbdom#the-dataset-module). Note that the `data-` prefix will be removed and dashes will be converted to camel case.

```tsx


// { dataset: { fooBar: 'baz' } }
```

### `is`

The `is` attribute can be used when you want to instantiate your customized built-in elements.

```tsx


// { is: 'custom-element' }
```

### `on*`

An attribute starting with `on` will passed to [the event listeners module](https://github.com/snabbdom/snabbdom#the-eventlisteners-module).

```tsx

{
console.log(e);
}}
/>
// { on: { click: f } }
```

### `list`, `role`, and `popoverTarget`

The `list`, the `role`, and the `popoverTarget` attributes will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).
Note that the attribute names will be lowercased.

```tsx


// { attrs: { role: 'button' } }

// { attrs: { list: 'options' } }

// { attrs: { popovertarget: 'popover' } }
```

### `$hook`

The `$hook` attribute is treated as [hooks](https://github.com/snabbdom/snabbdom#hooks).

```tsx


// { hook: { insert: f } }
```

For the sake of backward compatibility, `hook` (without the dollar sign) also behaves the same. However it is deprecated and will be removed in the future.

### `$key`

The `$key` attribute is treated as [a key](https://github.com/snabbdom/snabbdom#key--string--number).

```tsx


// { key: 'foo' }
```

For the sake of backward compatibility, `key` (without the dollar sign) also behaves the same. However it is deprecated and will be removed in the future.

### SVG elements

Attributes of `` and its descendant elements are passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).

### Built-in modules

In Snabbdom, different functionalities are delegated to separate modules. Values can be passed to them via attributes starting with `$`.

#### `$attrs` ([the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module))

```tsx


// { attrs: { class: 'foo' } }
```

#### `$class` ([the class module](https://github.com/snabbdom/snabbdom#the-class-module))

```tsx


// { class: { foo: true } }
```

#### `$dataset` ([the dataset module](https://github.com/snabbdom/snabbdom#the-dataset-module))

```tsx


// { dataset: { foo: 'bar' } }
```

#### `$on` ([the event listeners module](https://github.com/snabbdom/snabbdom#the-eventlisteners-module))

```tsx

{
console.log(e);
},
}}
/>
// { on: { click: f } }
```

#### `$props` ([the props module](https://github.com/snabbdom/snabbdom#the-props-module))

```tsx


// { props: { className: 'foo' } }
```

#### `$style` ([the style module](https://github.com/snabbdom/snabbdom#the-style-module))

```tsx


// { style: { opacity: '0', delayed: { opacity: '1' }, remove: { opacity: '0' } } }
```

#### Aliases

For the sake of backward compatibility, the following aliases are also defined. However they are deprecated and will be removed in the future.

| Attribute | Alias(es) |
| ---------- | ----------------- |
| `$attrs` | `attrs` |
| `$class` | `class` |
| `$dataset` | `data`, `dataset` |
| `$on` | `on` |
| `$props` | `props` |
| `$style` | `style` |

### Custom modules

Just like built-in modules, you can pass an arbitrary value to your custom modules via an attribute starting with `$`. For example, the expression `

` will yield `{ custom: { foo: 'bar' } }`.

#### Note for TypeScript users

Unlike built-in modules, we have no assumptions on what kind of values should be passed to custom modules. You have to augment `jsx.CustomModules` interface so that it will typecheck.

```ts
declare module '@herp-inc/snabbdom-jsx/jsx-runtime' {
namespace jsx {
interface CustomModules {
// Add your custom modules here
custom: {
foo: string;
};
}
}
}
```

## Components

A JSX component can be defined with a function with the signature of `(props: Props) => Snabbdom.VNodeChildElement`.

```tsx
import type Snabbdom from '@herp-inc/snabbdom-jsx';

type Props = {
children: Snabbdom.Node;
name: string;
};

const Component: Snabbdom.Component = ({ children, name }) => (


Hello, {name}!
{children}


);

const vnode = ;
```

## Caveats

- `boolean`, `null`, and `undefined` values are not be filtered out of the tree but rendered as comment nodes (for the sake of correct diffing)
- `snabbdom-pragma`-style `MODULE-PROPERTY` notation is not supported.

## Acknowledgements

The code base is based on these libraries:

- [`snabbdom`](https://www.npmjs.com/package/snabbdom)
- [`snabbdom-pragma`](https://www.npmjs.com/package/snabbdom-pragma)
- [`@types/react`](https://www.npmjs.com/package/@types/react)