reactive like `hankey` implementation of JSX for browser

Overview

deuce-x

reactive like 💩 implementation of JSX for browser.

this is opinion on how JSX should be implemented inspired by:

  1. curiosity about crank-js
  2. and hatred for react

requirements

this project requires:

  • deno

  • (modern) web browser

NOTE: it does not support any kind of server-side rendering.

usage

consists of:

  • jsx - jsx implementation

  • cmp - useful components

  • use - useful functions

jsx

provides:

  • createElement (or shorthand h) - transforms hyperscript into JSX.Element

  • render - renders arbitrary set of JSX.Elements into DOM Element

/** @jsx h */
import { h, render } from "https://deno.land/x/deuce_x/jsx.ts";

render(
  document.body, /* or any other element */
  <div>hello world</div>,
);

supported component types

primitives
// numbers
render(target, 0, 1.618033988749, 2.718281828459, 3.141592653589);

// booleans
render(target, true, false);

// strings
render(target, "hello", "world");
intrinsic HTML elements
render(
  target,
  <div>this is basic example<div>,
  <hr/>,
  <ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
  </ul>
)
arrays
render(
  target,
  [
    1.618033988749,
    true,
    "hello",
    <div>world</div>,
  ],
);
static components
type Props = { to: value };
const Hello = ({ to }: Props) => <div>hello, {to}!</div>;

render(
  target,
  <Hello to="world" />,
);
active components

this is component which maintains state.

type Props = { limit: value; delay: number };
async function* Counter({ limit, delay }: Props) {
  // define state
  let counter = 0;

  do {
    // render state
    yield <div>counting: {counter}</div>;

    await new Promise((resolve) => setTimeout(resolve, delay));

    // update state
    counter++;
  } while (counter < limit); // loop may be infinite

  // if function does not have return component will dissappear
  return <div>finished: {counter}</div>;
}

render(target, <Counter limit={16} delay={333} />);
future components

this is component which needs to perform asynchronous operations.

type Props = { url: string };
const FetchJSON = ({ url }: Props) =>
  fetch(url).then((response) => response.json());
// or it can be async
const FetchJSON2 = async ({ url }: Props) => {
  const response = await fetch(url);
  return response.json();
};
// which will effectively be the same
render(
  target,
  <FetchJSON url="https://example.com/sample.json" />,
  <FetchJSON2 url="https://example.com/sample.json" />,
);

cmp

provides:

  • Fragment - component to group other components

  • State - component to extract state from active components

Fragment

/** @jsx h */
/** @jsxFrag Fragment */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { Fragment } from "https://deno.land/x/deuce_x/cmp.ts";

const ComponentWithFragment = () => (
  <>
    <div>first</div>
    <div>second</div>
    <div>third</div>
  </>
);

fragments are syntax sugar for arrays.

State

/** @jsx h */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { State } from "https://deno.land/x/deuce_x/cmp.ts";

async function* stateProvider() {
  let iteration = 0;
  while (true) {
    yield { iteration };
    await new Promise((resolve) => setTimeout(resolve, 1000));
  }
}
type Props = { iteration: number };
const StatelessComponent = ({ iteration }: Props) => (
  <div>iteration #{iteration}</div>
);
const StatefulComponent = (
  <State input={stateProvider}>{StatelessComponent}</State>
);

use

provides:

  • useLink - get reference to dom elements when they are rendered

  • useWait - block execution until notice

  • useEvent - send event to subscribers

  • usePipe - event wrapped into iterator

  • useMux - multiplexed pipes

useLink

/** @jsx h */
/** @jsxFrag Fragment */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { Fragment } from "https://deno.land/x/deuce_x/cmp.ts";
import { useLink } from "https://deno.land/x/deuce_x/use.ts";

const [socket, plug] = useLink<HTMLInputElement>();

const Interactive = () => (
  <>
    <input socket={socket} />
    <button
      onClick={async () => {
        alert(`you have entered: ${(await plug).value}`);
      }}
    />
  </>
);

useWait

/** @jsx h */
/** @jsxFrag Fragment */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { Fragment } from "https://deno.land/x/deuce_x/cmp.ts";
import { useWait } from "https://deno.land/x/deuce_x/use.ts";

const [lock, release] = useWait();
const ClickCounter = async function* () {
  let clicks = 0;
  while (true) {
    yield `clicks so far: ${clicks}`;
    await lock(); // execution will stop here until someone invokes release
    clicks++;
  }
};

render(
  target,
  <>
    <ClickCounter />
    <button onClick={release}>click!</button>
  </>,
);

useEvent

/** @jsx h */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { useEvent } from "https://deno.land/x/deuce_x/use.ts";

const [emitEvent, onEvent] = useEvent<string>();
onEvent((event) => alert(`alert received: ${event}`));

render(
  target,
  <button onClick={() => emitEvent("achtung!")}>alert me!</button>,
);

usePipe

/** @jsx h */
/** @jsxFrag Fragment */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { Fragment } from "https://deno.land/x/deuce_x/cmp.ts";
import { usePipe } from "https://deno.land/x/deuce_x/use.ts";

const [sendToPipe, eventPipe] = usePipe<void>();
type PipeListenerProps = { input: PipeOutput<void> };
const PipeListener = async function* ({ input }: PipeListenerProps) {
  let events = 0;
  for await (const event of input()) {
    events++;
    yield `received ${events} events so far`;
  }
};

render(
  target,
  <>
    <button onClick={() => sendToPipe()}>generate pipe event</button>
    <PipeListener input={eventPipe} />
  </>,
);

useMux

/** @jsx h */
/** @jsxFrag Fragment */
import { h } from "https://deno.land/x/deuce_x/jsx.ts";
import { Fragment } from "https://deno.land/x/deuce_x/cmp.ts";
import { useLink, useMux, usePipe } from "https://deno.land/x/deuce_x/use.ts";

type CreateEvent = { type: "create"; value: string };
type RemoveEvent = { type: "remove"; value: number };

const [create, createPipe] = usePipe<string>();
const [remove, removePipe] = usePipe<string>();
const eventPipe = useMux({
  create: createPipe,
  remove: removePipe,
});

type ListProps = { events: Pipe<CreateEvent | RemoveEvent> };
const List = async function* ({ input }: PipeListenerProps) {
  const list: string[] = [];
  for await (const event of input()) {
    switch (event) {
      case "create":
        list.push(event.value);
        break;
      case "remove":
        list.splice(event.value, 1);
        break;
    }
    yield list.map((record, id) => (
      <div>
        <span>{id}.</span>
        <span>{record}</span>
      </div>
    ));
  }
};

render(
  target,
  <>
    <div>
      <input type="text" socket={recordSocket} />
      <button
        onClick={async () => {
          const input = (await recordPlug);
          create(input.value);
          input.value = "";
        }}
      >
        create
      </button>
    </div>
    <div>
      <input type="text" socket={recordSocket} />
      <button
        onClick={async () => {
          const input = (await recordPlug);
          remove(+input.value);
          input.value = "";
        }}
      >
        remove
      </button>
    </div>
    <List input={eventPipe} />
  </>,
);

examples

rerer to:

  • demo provides examples of the above features you can experiment with

  • todo implementation example

TODO

  • refactor TODO demo
  • support SVG namespace
  • generate jsx type definitions from standard
  • write more docs
  • check for memory leaks
  • check for performance ( --> optimize )
Owner
Alexander Betaev
Alexander Betaev
🍼 650B Virtual DOM - Use reactive JSX with minimal overhead

?? little-vdom Forked from developit's little-vdom gist. npm: npm i @luwes/little-vdom cdn: unpkg.com/@luwes/little-vdom 650B Virtual DOM Components S

wesley luyten 7 Jan 17, 2022
:point_up::running: Modern Relay Starter Kit - Integrated with Relay, GraphQL, Express, ES6/ES7, JSX, Webpack, Babel, Material Design Lite, and PostCSS

Relay Fullstack is a Relay scaffolding application that aims to help you get up and running a project without worrying about integrating tools. It com

Varayut Lerdkanlayanawat 985 Jan 12, 2022
Vanilla JSX + HTML + CSS compiler and static-site generator (SSG)

VANIL Vanilla JSX + HTML + CSS compiler and static-site generator (SSG) VANIL is a compiler and static site generator (SSG) that combines TSX/JSX+HTML

Aron Homberg 3 Jan 10, 2022
Universal rendering for Preact: render JSX and Preact components to HTML.

preact-render-to-string Render JSX and Preact components to an HTML string. Works in Node & the browser, making it useful for universal/isomorphic ren

Preact 452 Jan 19, 2022
React component for highlighting js and jsx code with copy to clipboard functionallity

✨ ??️ React Highlight ✨ ??️ React component for highlighting js and jsx code wit

Jin Jose Manuel 9 Jan 18, 2022
A react library to convert react jsx svg component to image dataurl.

Jsx To Png A react library to convert react jsx svg component to image dataurl. Motivation I wrote many react-svg components. Practically, I need to c

qefeng 1 Dec 23, 2021
Nosx - Better API for React — without JSX

NoSX Better API for React — without JSX Ever wondered how you could use React wi

Jesse Luoto 5 Jan 7, 2022
Angular - Best Practices of Reactive Programming.

This project is a study system in Angular and implementing using the best practices of reactive programming.

Miguel Müller 3 Jan 2, 2022
A frontend Framework for building B2B applications running in the browser on top of REST/GraphQL APIs, using ES6, React and Material Design

react-admin A frontend Framework for building data-driven applications running in the browser on top of REST/GraphQL APIs, using ES6, React and Materi

marmelab 18.7k Jan 16, 2022
Building web, Electron, Cordova and Chrome apps, and cross-browser extensions with React, Redux and Webpack. "Write once, deploy everywhere" concept in practice.

CrossBuilder Building web, Electron, Cordova and Chrome apps, and cross-browser extensions that use Redux actions for messaging. Redux states are sync

Mihail Diordiev 490 Sep 14, 2021
Building web, Electron, Cordova and Chrome apps, and cross-browser extensions with React, Redux and Webpack. "Write once, deploy everywhere" concept in practice.

CrossBuilder Building web, Electron, Cordova and Chrome apps, and cross-browser extensions that use Redux actions for messaging. Redux states are sync

Mihail Diordiev 490 Sep 14, 2021
Comprehensive (but unofficial) fitbit web-api handler for node-js and browser

This library supports both browser and nodejs. Install Install via npm or yarn:

MyAlyce 2 Dec 27, 2021
Ext-react - A starter repo for building browser extensions with React and Typescript

Web Extensions React starter A starter repo for building browser extensions with

Okanovic Dragan 9 Jan 15, 2022
Boilerplate for react universal (isomorphic) application based on flux architecture (redux implementation)

Redux universal boilerplate Boilerplate for react universal application building on flux architecture based on redux implementation. Boilerplate based

Sergey 74 Sep 17, 2021
A collection of 14 different React projects like Music Player, Weather App, Crypto Tracker, Chat Room, Currency Converter, COVID Tracker, To-do and Expense App, Color Generator etc.

Simple React Projects Note: If any project does not work Online download the project and run on your local Storage (Error is coming due to Local Stora

MD Yasin 12 Jan 16, 2022
React Dashboard made with Material UI’s components. Our pro template contains features like TypeScript version, authentication system with Firebase and Auth0 plus many other

Material Kit - React Free React Admin Dashboard made with Material UI's components, React and of course create-react-app to boost your app development

Devias 3.5k Jan 13, 2022
A template repo for creating react-ts apps based on vite. Libs like axios, antd, @apollo/client, eslint, stylelint, react-router-dom and @syy11cn/config-router are pre-installed.

Template Repo for React + Typescript + Vite Introduction This is a template repo for projects built with react and typescript on the basis of vite. Fe

Yiyang Sun 12 Dec 17, 2021
Instagram Clone | A place where you could share photos, like media, and follow peoples.

Apollo Instagram Clone Instagram Clone | Social Media Application Web UI Mobile UI Stacks Used Frontend Backend React GraphQL + Express TailwindCSS Ty

Aseer KT 20 Jan 1, 2022
The react HOC for create custom players with any styles you like

reaplay the react HOC for create custom players with any styles you like give me your tracks, i will give you the all function and variable you need t

Amir 5 Jan 8, 2022