@ibyra/angico
TypeScript icon, indicating that this package has built-in type declarations

1.0.6 • Public • Published

Angico

A small JSX async-rendering library.

View on NPM License

Installation

Use the npm package manager or bun runtime to install Angico

npm i @ibyra/angico
bun i @ibyra/angico

Usage

Setting up the configuration

Firstly, you'll need to configure your JSX transformer to use Angico.

If you are using Typescript, you'll need to set the JSX properties your tsconfig.json as follow:

{
  "jsx": "react-jsx",
  "jsxImportSource": "@ibyra/angico"
}

If you are using other transpiler, like Babel, you can use these pragma comments on the top of the your source file.

/** @jsxImportSource @ibyra/angico */

var descriptions = items.map((item) => (
  <>
    <dt>{item.name}</dt>
    <dd>{item.value}</dd>
  </>
));

Authoring JSX

After setting up the configuration, using Angico is very similar to any other JSX library. You can create and compose your components/fragments, even if they are asynchronous.

function Input(props: { type: 'text' | 'number' }): JSX.Element {
  return <input type={props.type} />;
}

type BoxProps = {
  width: JSX.StringNumber;
  height: JSX.StringNumber;
  children?: JSX.Children;
};

async function AsyncBox(props: BoxProps): JSX.AsyncElement {
  const { height, width, children } = props;
  const style = `height: ${height}px; width: ${width}px`;
  await timeout(10);
  return (
    <div style={style} class="box">
      {timeout(10).then(() => children)}
    </div>
  );
}

// Just to here to simulate an asynchronous operation
function timeout(ms: number): Promise<number> {
  return new Promise((resolve) => setTimeout(resolve, ms, ms));
}

const box = (
  <AsyncBox height="100" width="100">
    <Input type="number" />
    Type a number.
    <button type="submit">Submit</button>
  </AsyncBox>
);

console.log(box); // FunctionElement { ... }

As you can see, the JSX does not return an rendered version, but a instance of FunctionElement instead. This is because Angico does not renders anything immediately, only when it is required to do so.

Rendering JSX into a string

You can request an JSX element to render into a string using the render function, also available on Angico package.

import { render } from '@ibyra/angico';

// ...

const box = (
  <AsyncBox height="100" width="100">
    <Input type="number" />
    Type a number.
    <button type="submit">Submit</button>
  </AsyncBox>
);

const rendered = await render(box);

const expected = `<div style="height: 100px; width: 100px" class="box"><input type="number"/>Type a number.<button type="submit">Submit</button></div>`;

assert(rendered === expected);

HTML, SVG, MathML, XML…

You can use Angico to render any XML markup you desire. You can use SVG out of the box!

import Angico from '@ibyra/angico';

export type IconProps = JSX.SVGSVGTag & {
  fill?: string;
};

// The "envelope-simple" icon provided by @phosphor-icons/core
// https://github.com/phosphor-icons/core
export function EnvelopeSimple(props: IconProps): JSX.Element {
  const {
    fill = 'currentColor',
    height = '1.5em',
    width = '1.5em',
    ...rest
  } = props;
  return (
    <svg
      width={width}
      height={height}
      aria-hidden="true"
      inert
      {...rest}
      viewBox="0 0 256 256"
    >
      <path
        fill={fill}
        d="M224 48H32a8 8 0 0 0-8 8v136a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a8 8 0 0 0-8-8Zm-20.57 16L128 133.15L52.57 64ZM216 192H40V74.19l82.59 75.71a8 8 0 0 0 10.82 0L216 74.19V192Z"
      />
    </svg>
  );
}

[!WARNING] The current support for SVG and MathML is limited, only a few elements and attributes are defined. We aim to improve the support in the future.

Extending type definitions

Sometimes you want to extend the definitions of the JSX available intrinsic elements; e.g, when you are using an attribute-based JS library like HTMX or Alpine.js, or when you have some custom elements in your markup. You can extend the JSX.IntrinsicElements or HTMLAttributes interfaces with your custom definitions.

declare global {
  namespace JSX {
    interface HTMLAttributes {
      // HTMX attributes
      [hx: `hx-${string}`]: string | boolean;
    }

    interface OpenableAttributes extends HTMLAttributes {
      open?: boolean;
    }

    interface IntrinsicElements {
      ['my-custom-component']: OpenableAttributes;
    }
  }
}

Roadmap

  • Improve HTML elements and attributes typings;
  • Improve support for WAI-ARIA attributes typings;
  • Support all SVG elements and attributes typings;
  • Support all MathML elements and attributes typings;
  • Support streamed rendering;

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT © Ibyra

Package Sidebar

Install

npm i @ibyra/angico

Weekly Downloads

1

Version

1.0.6

License

MIT

Unpacked Size

105 kB

Total Files

7

Last publish

Collaborators

  • maxroecker