Skip to content

jebbari-mohammed/mini-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mini-Framework

Overview

Mini-Framework is a lightweight JavaScript framework for building interactive web applications. It features a virtual DOM, JSX-like API, hooks for state and effects, hash-based routing, and declarative event handling. The goal is to provide a simple, modern development experience with minimal code.


Features

  • Virtual DOM: Efficiently updates the real DOM by diffing virtual trees.
  • JSX-like API: Use a jsx function to describe UI elements and components.
  • Hooks: Includes useState, useEffect, and useRef for state and side effects.
  • Routing: Hash-based router for single-page app navigation.
  • Declarative Events: Attach events directly in your JSX-like code.

How It Works

  • You write components as functions that return virtual DOM objects using the jsx API.
  • The framework renders these to the real DOM and updates efficiently on state changes.
  • Hooks provide state and lifecycle management in a functional style.
  • The router listens to URL hash changes and updates the view accordingly.

Quick Start

1. Basic HTML Setup

<!DOCTYPE html>
<html>
  <head>
    <title>Mini-Framework App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="app.js"></script>
  </body>
</html>

2. Import the Framework

import { jsx } from "./framework/jsx.js";
import { Render } from "./framework/render.js";
import { useState, useEffect, useRef } from "./framework/hooks.js";
import { Router } from "./framework/router.js";

3. Your First Component

function HelloWorld() {
  const [name, setName] = useState("World");
  return jsx("div", null,
    jsx("h1", null, `Hello, ${name}!`),
    jsx("input", {
      value: name,
      onInput: e => setName(e.target.value)
    })
  );
}

Render.render(HelloWorld, document.getElementById("app"));

Code Examples

Creating Elements

const el = jsx("button", { class: "btn", id: "submit-btn" }, "Click me");

Adding Attributes

const input = jsx("input", { type: "email", placeholder: "Enter email", required: true });

Events

const button = jsx("button", { onClick: () => alert("Clicked!") }, "Click");

Nesting

const form = jsx("form", null,
  jsx("input", { type: "text" }),
  jsx("button", { type: "submit" }, "Submit")
);

State Management with Hooks

useState

function Counter() {
  const [count, setCount] = useState(0);
  return jsx("div", null,
    jsx("span", null, `Count: ${count}`),
    jsx("button", { onClick: () => setCount(count + 1) }, "+"),
    jsx("button", { onClick: () => setCount(count - 1) }, "-")
  );
}

useEffect

function Timer() {
  const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(id);
  }, []);
  return jsx("div", null, `Seconds: ${seconds}`);
}

useRef

function FocusInput() {
  const inputRef = useRef();
  return jsx("div", null,
    jsx("input", { ref: inputRef, type: "text" }),
    jsx("button", { onClick: () => inputRef.current && inputRef.current.focus() }, "Focus Input")
  );
}

Routing Example

Router.initRouter();

function App() {
  const { currentRoute, navigate } = Router.useRouter();
  return jsx("div", null,
    jsx("nav", null,
      jsx("a", {
        href: "#/",
        onClick: e => { e.preventDefault(); navigate("/"); }
      }, "Home"),
      jsx("a", {
        href: "#/about",
        onClick: e => { e.preventDefault(); navigate("/about"); }
      }, "About")
    ),
    currentRoute === "/" && jsx("div", null, "Home Page"),
    currentRoute === "/about" && jsx("div", null, "About Page")
  );
}

TodoMVC Example

function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState("");
  const inputRef = useRef();

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, { id: Date.now(), text: input, completed: false }]);
      setInput("");
    }
  };

  const toggleTodo = id => setTodos(
    todos.map(t => t.id === id ? { ...t, completed: !t.completed } : t)
  );
  const deleteTodo = id => setTodos(todos.filter(t => t.id !== id));

  return jsx("div", { class: "todo-app" },
    jsx("h1", null, "Todo List"),
    jsx("input", {
      ref: inputRef,
      type: "text",
      value: input,
      onInput: e => setInput(e.target.value),
      onKeyDown: e => { if (e.key === "Enter") addTodo(); },
      placeholder: "Add a new todo..."
    }),
    jsx("button", { onClick: addTodo }, "Add"),
    jsx("ul", { class: "todo-list" },
      ...todos.map(todo => jsx("li", {
        key: todo.id,
        class: todo.completed ? "completed" : ""
      },
        jsx("input", {
          type: "checkbox",
          checked: todo.completed,
          onChange: () => toggleTodo(todo.id)
        }),
        jsx("span", null, todo.text),
        jsx("button", { onClick: () => deleteTodo(todo.id) }, "Delete")
      ))
    )
  );
}

Render.render(TodoApp, document.getElementById("app"));

Why This Approach?

  • Virtual DOM: Fast, predictable UI updates.
  • JSX-like API: Familiar, expressive, and composable.
  • Hooks: Simple, functional state and effect management.
  • Routing: SPA navigation without server config.
  • Declarative Events: Cleaner code, less boilerplate.

File Structure

mini-framework/
├── framework/
│   ├── jsx.js          # JSX-like element creation
│   ├── render.js       # Virtual DOM rendering
│   ├── hooks.js        # State management hooks
│   ├── router.js       # Hash-based routing
│   ├── virtual-dom.js  # Virtual DOM implementation
│   └── dom-diff.js     # DOM diffing algorithm
├── app.js              # Main application file
├── index.html          # HTML entry point
├── style.css           # Application styles
└── README.md           # This documentation

Best Practices

  • Keep components focused and single-purpose
  • Use hooks for local state
  • Use descriptive function names for event handlers
  • Clean up side effects in useEffect return functions
  • Use meaningful variable names and comments

Troubleshooting

  • Component not rendering: Make sure to call Render.render(YourComponent, mountNode)
  • State not updating: Use the setter function from useState
  • Events not working: Event names must start with on (e.g., onClick)
  • Routing not working: Call Router.initRouter() before using routing
  • Check the browser console for errors

Browser Support

  • ES6 modules
  • Arrow functions
  • Template literals
  • Array methods (map, filter, reduce)

Conclusion

This mini-framework provides a solid foundation for building interactive web applications. Its modular architecture makes it easy to understand and extend, while its familiar syntax makes it accessible to developers with experience in modern JavaScript frameworks.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •