Skip to content

denshya/proton

Repository files navigation

Proton 🔵

Fast, Ultra Light weight (~5kb gzip), DOM-first, Rootless, with Native Observables, No configuration, Component-based UI library with Android-style View inflation.

Based on No Framework Principle.

Playground

Install

bun i @denshya/proton

For the JSX and types to work properly, you should add this to your tsconfig.json/jsconfig.json

{
  "compilerOptions": {
    // ...
    "jsx": "react-jsx",
    "jsxImportSource": "@denshya/proton/jsx/virtual",
    // ...
  }
}

What is "Rootless"?

It means you don't have to hijack an element in order to render the App, it cancles Root Component and Host element completely.

That is a novel wording, another good phrase is "Reversed Element Factory Ownership". These all stand for a component (or element) factory function producing/providing ownership to owned elements rather than being a side-effects function, which only modifies given element.

From querying the element and modifying

const element = document.getElementById("id")
makeWidget(element)

function makeWidget(element) {
  element.style = "..."
  // ... Some other styling and structure
}

To creating desired element and sharing ownership

function createWidget() { // returns element instead.
  const element = document.createElement("div")
  element.style = "..."
  // ... Some other styling and structure

  return element
}

This forces you to find the exact place where the new element should go, which may be tricky, this what Proton solves with JSX while still letting you choose the place to attach or reattach Proton Component.

Which allows you do to this: (Somewhat an alternative to Web Components)

function Widget() {
  return <div style={...} /> // Some code.
}
Widget.Standalone = inflator.inflate(<Widget />)

const container = document.querySelector(".container")
container?.append(Widget.Standalone)

Observables Allowed in JSX

The turning point is that JSX element attributes and children can consume WICG Observables, meaning practically any library can be used as a State Manager.

const text = new State("")

const button = document.getElementById("button")
button.append(inflate.inflate(<div>{text}</div>))

Continue reading about JSX Reactivity

Customization

Adding your own JSX Attribute for any element is as easy as never.

For example, classMods - it will ensure BEM for elements without anoying imports.

inflator.jsxAttributes.set("classMods", context => {
  if (context.value == null) return
  context.bind("className", bem(context.props.className, context.value))
})

More about customization

Fault Tolerance

Unlike to React - Proton will not propogate thrown errors to parents - errors in Children will not break Parents while you still can catch them.

function Child() { throw new Error("Test") }
function Parent(this: Proton.Component) { return <div>123<Child /></div> }

document.body.append(inflate.inflate(<Parent />)) // Will render `123` without errors.

Learn how you catch errors

Open Internals

To maintain open internals this library uses Classes instead of Functions as factories and uses private identifier in TypeScript, which gives you propert types while not stopping you from experimenting with internal variables and even allowing you to override them in convential way.

Similar Libraries

If you want manage your components in a somewhat complex way (like in React), you can continue reading this, but otherwise you may want to consider these alternatives:

Getting Started

function App() {
  return <div>Hello World!</div>
}

const inflator = new WebInflator
const AppView = inflator.inflate(<App />)

document.getElementById("root").replaceChildren(AppView)

JSX

Proton supports React-like JSX, except that it maps directly to Document elements and allows any value to be put into attributes or as children of any elements.

<div className="product-card">
  <h2>Title</h2>
  <p>Description</p>
  <img src="/static/product-card.jpg" />

  // You can put your weird staff.
  <aside id={new MyIdObject} />
</div>

Learn more about Inflator to provide custom handlers.

TypeScript

Report if there are anything uncovered for TypeScript.

FAQ

Does React hooks work in Proton? No, but it's very extesible so probably some enthusiasts might implement it. BTW, even though libraries from other "frameworks" won't work in Proton, libraries for Proton are supposed to work in other frameworks too.