phantom
👻
A Redux powered, state—reactive DOM rendering engine.
npm i @sidiousvic/phantom
phantom
lets you build state—reactive UIs using raw HTML in functional components.
export default function Pizza(slices) {
return `
<div id="pizza-box">
<h1 data-phantom="${slices}" id="slices-h1">${slices}</h1>
</div>
`;
}
phantom
swaps DOM nodes for you.
You update data via Redux, and
🚀 Get launched
🍕 Manage state
❓ FAQ
🔧 Developers
🚀 Get launched
1. Create a Redux Store
phantom
will couple with Redux to subscribe DOM rendering to state updates.
Redux npm i redux
Install Show code ↯
import { createStore } from "redux";
const data = {
slices: ["🍕", "🍕", "🍕"],
};
function reducer(state = data, action) {
switch (action.type) {
case "EAT_SLICE":
// remove a slice from array
return { ...state, slices: state.slices.slice(0, -1) };
default:
return state;
}
}
const store = createStore(reducer);
export default reduxStore;
phantom
component
2. Write an entry phantom
components are functions that return HTML template strings. This allows you to inject dynamic data (including other components) via template literals ${}
.
We leet-html
extension for VSCode is recommended for HTML template highlighting.
Show code ↯
function phantomComponent() {
return `
${Pizza()} // inject the Pizza component from above
`;
}
phantom.launch()
3. Initialize and Start the phantom
engine with the reduxStore
and a phantomElement
.
Show code ↯
import phantom from "@sidiousvic/phantom";
import reduxStore from "./reduxStore.js";
import Pizza from "./ui/Pizza.js";
export const { fire, data, launch } = phantom(reduxStore, phantomComponent);
launch(); // initial render
phantom
will expose three key methods: fire
, data
, and launch
.
fire
and data
are only syntactic pointers to the reduxStore
's dispatch
and getState
methods respectively. You are welcome to avoid them and call the store directly for action dispatching and state getting.
launch
will perform the initial DOM render on call.
🍕 Manage state
data()
to read state from the Redux store.
Use function phantomComponent() {
const { slices } = data();
return `
${Pizza(slices)}
`;
}
Pass data as arguments to components, and use them in your HTML templating.
export default function Pizza(slices) {
return `
<div id="pizza-box">
<h1 data-phantom="${slices}" id="slices-h1">${slices}</h1>
</div>
`;
}
data-phantom attribute. |
---|
|
---|
fire()
to fire an action and trigger a state update + re—render.
Use document.addEventListener("click", eatPizza);
function eatPizza(e) {
if (e.target.id === "slices-h1") {
fire({ type: "EAT_PIZZA" }); // fire an action to the store
}
}
❓ FAQ
phantom
?
Why use
🐼
A baby panda dies every time you choose a 1MB+* industrial—level frontend framework to code a pomodoro or a personal portfolio page. Show rationale ↯
phantom
is the bike you need.
You don't drive to the corner store, but walking is overrated.
🖍 Declarative
With phantom
, you can write markup in a declarative way ala JSX using raw HTML strings, and inject dynamic data using template literals—staying fully JS native.
🍕 Component—based
phantom
lets you divide your UI into components, abstracting markup into composable functions.
🧪 Reactive
The phantom
engine integrates with your Redux store and subscribes to state updates. It swaps nodes when their data changes.
👩🏾🏭 Closer to the JS metal
phantom
only helps with DOM rendering. Listeners, effects, style manipulation, routing—the fun stuff—is still in your hands. 🙌🏼
No JSX, no complex API, no syntactic hyperglycemia.
phantom
is for JavaScript devs.○∆
React is for React devs. Vue is for slightly hipster devs. * unpacked size of ReactDOM is 3MB. Vue is 2.98MB. Phantom is < 40 kB.
○ phantom
users may be the hipsterest of them all.
∆ Angular? What is Angular?
phantom
use a virtual DOM?
Does When a component's data changes, phantom
will re—render that node in the DOM by diffing its internal PseudoDOM, an object representation of the DOM.
data-phantom
attribute in stateful elements?
Why should I always include the In order for your element to be reactive to data changes, phantom
needs to know which nodes are bound to the updated data. Specifying a data-phantom="${yourData}"
attribute is a simple way to do that.
id
attribute in stateful elements?
Why should I always include an Two reasons, one philosophical, one technical:
-
Once you get into the habit, specifying
id
s results in remarkably declarative markup. It encourages you to think about each element's specific function in the UI and also helps to identify it visually. -
id
is one of the mechanisms that thephantom
engine uses to detect which nodes to update.
🔧 Developers
phantom
is written in TypeScript and bundled using Webpack.
Instructions
- Read the Code of Conduct
- Fork the repo on GitHub
- Clone the project to your machine
-
Install dependencies with
npm i
- Commit updates to your own branch
- Push your work to your fork
- Pull request for your changes to be reviewed
Scripts
npm run build
generates a static build in dist/
.
npm run test
runs the tests located in __tests__/
.
npm run example/[example name]
runs an example app from examples/
via webpack-dev-server
.
Examples
There are several examples you can run, each furnished with their own devServer
configuration.
Use npm run example/[example name]
and navigate to the url that appears in your terminal.