@moali1071/mini-framework
v1.0.3
Published
my mini framework
Readme
🧩 Mini Framework
A minimal, TypeScript-based reactive framework for building lightweight web applications using component functions, simple state management, declarative DOM event binding, and client-side routing — with no external dependencies.
📆 Installation
npm install @moali1071/mini-framework🚀 Quick Overview
This framework enables you to:
- Build apps using function-based components that return HTML strings.
- Manage reactive state scoped to a specific root.
- Attach event listeners declaratively using
data-on<event>attributes. - Handle routing with a simple route-to-component map.
🏗️ App Structure
A typical setup involves:
An HTML container where your app will be mounted:
<div id="app"></div>Function-based components that return template strings:
// components/Home.ts export function Home(state) { return `<button data-onclick="increment">Count: ${state.count}</button>`; }An initial state object that includes all data tied to your root:
const initialState = { count: 0 };**Calling **``, passing in your state and root element:
const { state, mount, setHandlers } = render(initialState, document.getElementById("app"));Mounting components and setting event handlers:
import { Home } from "./components/Home"; import { handlers } from "./handlers/homeHandlers"; mount(Home); setHandlers(handlers);
📘 API Reference
createDOMFromString(template: string): DocumentFragment
Converts an HTML string into a DocumentFragment you can insert into the DOM.
Used internally by render, but can also be used manually for DOM manipulation.
setupEvents(root: Element, handlers: { [key: string]: (e: Event) => void })
Scans the DOM for attributes like data-onclick="handlerName" and binds the relevant function from the handlers object.
- The event type is derived from the attribute (
data-onclick,data-oninput, etc.). - The handler name must match a key in the
handlersobject. - Used internally whenever a component mounts or rerenders.
createState<T>(initialState, onChange)
Creates a reactive state object.
Returns an object with:
getState()– returns the current statesetState(state)– updates the statesubscribe(callback)– runs the callback on every state changestate– the current state value (for reference only; prefergetState())
Used internally by render.
render<T>(initialState, rootElement)
Binds the given initialState to the specified DOM root.
Returns an object with:
state– a state object containing:getState()– fetches the latest state snapshot.setState(partialState)– updates state properties and re-renders.subscribe(callback)– run side effects when state changes.state– a reference to the state object (avoid direct mutation).
mount(component)– renders a component to the root. The component must be a function that accepts the state and returns a string.setHandlers(handlers)– sets all event handlers used by this root. Each key is the handler name, and the value is the function to run.
📝 Component Structure
A component must be a pure function that accepts a state object and returns a string.
function Counter(state) {
return `
<div>
<p>Count: ${state.count}</p>
<button data-onclick="increment">+</button>
</div>
`;
}It is recommended (but not required) to place all components in a components/ directory for better organization.
🎯 Event Binding
You can declaratively add event listeners in templates using data-on<event> attributes:
<button data-onclick="increment">+</button>These are mapped to handler functions via setHandlers():
setHandlers({
increment: () => state.setState({ count: state.getState().count + 1 }),
});It’s recommended to organize handler functions in files such as:
handlers/
homeHandlers.ts
profileHandlers.tsinitRouter<T>(routes, mount)
Sets up client-side routing using history.pushState.
Parameters:
routes– An object where:- Keys are route paths (e.g.,
/,/about) - Values are the component functions to mount.
Optionally, include a
"404"key to render when the path isn't found.- Keys are route paths (e.g.,
mount– Themountfunction returned fromrender(), used to display the component for the current route.
Returns:
navigate(path: string)– navigates to a route and renders the appropriate component.
Example:
const routes = {
"/": Home,
"/about": About,
"404": NotFound,
};
const router = initRouter(routes, mount);
router.navigate("/about"); // navigates to /about and renders <About />📂 Recommended Directory Structure
/my-app
├── index.html
├── main.ts
├── components/
│ ├── Home.ts
│ └── About.ts
└── handlers/
├── homeHandlers.ts
└── aboutHandlers.ts📐 TypeScript Types
The framework includes the following helpful types:
EventHandlers
type EventHandlers = {
[key: string]: (e: Event) => void;
};Used with setupEvents() and render().setHandlers() to define your DOM event handlers.
StateObject<T>
type StateObject<T> = {
state: T;
setState: (newState: Partial<T>) => void;
getState: () => T;
subscribe: (fn: (state: T) => void) => void;
};Returned from createState<T>() and from render().state. It represents your app's reactive state.
ComponentFn<T>
type ComponentFn<T> = (state: T) => string;A function that returns an HTML string representation of the UI based on current state.
Routes<T>
type Routes<T> = {
[path: string]: ComponentFn<T>;
};Used in initRouter() to define your app's routes.
