Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/ncpa0/vanilla-jsx


https://github.com/ncpa0/vanilla-jsx

Last synced: about 1 month ago
JSON representation

Awesome Lists containing this project

README

        

*VanillaJSX provides a syntactic sugar for creating HTMLElements*

### Example

These two snippets are equivalent:

```typescript
const container = document.createElement('div');
const header = document.createElement('h1');
header.textContent = 'Hello, world!';
header.classList.add('custom-header');
div.setAttribute('id', 'header-container');
container.appendChild(header);
```

```tsx
const container = (


Hello, world!



);
```

## TypeScript and build step

To enable TypeScript support set these options in your `tsconfig.json`:

```json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@ncpa0cpl/vanilla-jsx"
}
}
```

Similar options will need to be set in the build tool you are using. For example the following option should be used in `esbuild`:

```javascript
esbuild
.build({
jsxImportSource: "@ncpa0cpl/vanilla-jsx",
...rest
})
```

## Signals

On top of the basic syntax sugar it is also possible to easily bind signals to element attributes, children and listeners.

VanillaJSX does not enforce any specific signal implementation, but it does provide one if you wish to use it. For a given signal to be able to be used it needs to be registered with the `SignalsReg`:

```typescript
import { SignalsReg } from "@ncpa0cpl/vanilla-jsx";
import { MySignal } from "./my-signal";

class MySignalInterop {
is(maybeSignal: unknown): maybeSignal is MySignal {
return maybeSignal instanceof MySignal;
}
add(signal: MySignal, listener: (value: any) => void) {
signal.addListener(listener);
listener(signal.value);
return () => signal.removeListener(listener);
}
}

SignalsReg.register(new MySignalInterop());

declare global {
namespace JSX {
interface SupportedSignals {
mySignal: MySignal;
}
}
}
```

#### Provided interops

There's a few interops provided by default that can be imported and registered:

```typescript
import {
SignalsReg,
JsSignalInterop,
MiniSignalInterop,
PreactSignalInterop,
} from "@ncpa0cpl/vanilla-jsx";

SignalsReg.register(new JsSignalInterop());
SignalsReg.register(new MiniSignalInterop());
SignalsReg.register(new PreactSignalInterop());
```

### VanillaJSX Signals usage example

```tsx
import { sig } from "@ncpa0cpl/vanilla-jsx/signals";

function getCounterComponent() {
const counter = sig(0);

const onClick = () => {
counter.dispatch(current => current + 1);
};

return (


`counter_${c}`)}
onClick={onClick}
>
Click me!

{counter}



);
};
```

### Conditional rendering and maps

It's possible to achieve conditional rendering or maping a list of elements by using the `derive()` method of the provided signal implementation:

```tsx
import { sig, Signal } from "@ncpa0cpl/vanilla-jsx/signals";

function displayElements(elems: Signal) {
return


{elems.derive(list => {
if (list.length === 0) {
return

No elements to display

;
}
return list.map((elem, i) =>

{elem}

);
})}
;
}
```

However in case of another signal implementation or for more optimized rendering of lists a few base components are available:

####

```tsx
import { If } from "@ncpa0cpl/vanilla-jsx";
import { sig } from "@ncpa0cpl/vanilla-jsx/signals";

function conditionComponent() {
const someCondition = sig(false);

return


Condition Met!

}
else={() =>

Condition Not Met!

}
/>
;
}
```

####

```tsx
import { Switch, Case } from "@ncpa0cpl/vanilla-jsx";

enum MyEnum {
A, B, C
}

function displayOneOf(value: JSX.Signal) {
return




{() =>
Case A
}


{() =>
Case B
}


{() =>
Default case
}


;
}
```

####

```tsx
import { Range } from "@ncpa0cpl/vanilla-jsx";

function displayList(list: JSX.Signal) {
return


}
>
{(value) =>
  • {value}
  • }

    ;
    }
    ```