Skip to content

ProjectPenrose/paradox

Repository files navigation

<Paradox/> Not another javascript framework!

Paradox is just a simple vanilla javascript library for DOM manipulation.
Hopefully it will ease your development while learning
· Report Bugs · Request Features

GitHub contributors GitHub commit activity GitHub issues GitHub pull requests

IMPORTANT: Things are changing a lot right now, so please be patient, this is a work in progress

Table of Contents

About The Project

Working on cool stuff to say here. stay tuned and please be patient, this is a work in progress.

Contributions are welcome thogh xd, please start a discussion to discuss what you would like to change, add or remove and we can figure it out together.

Link to the npm package

Getting Started

Paradox is a simple vanilla javascript library for DOM manipulation that also provides a simple router and PubSub implementation.

Requirements

  • Node.js >= v16.16.0 (For development mode)

Installation

  1. Clone the repo
    git clone git@github.com:ProjectPenrose/paradox.git
  2. Install NPM packages
    cd penrose-paradox
    npm install

Usage

Now things can change depending on what you want to do, so here are some options:

Paradox from npm

You can use paradox in a project that uses npm, all you need before getting started is to have webpack set with babel loader.

Then you can install it like this:

npm i penrose-paradox

Then you can import it like this:

import Paradox from "penrose-paradox";

Now you'll have access to all the paradox features in your node projects.

Project structure example

Here's an example of a project structure that uses paradox:

. # root
├── app
│   ├── index.js
│   └── index.html
├── dist
│   ├── css
│   │   └── main.css
│   └── js
│       └── bundle.js
├── node_modules
├── package.json
├── package-lock.json
├── server
│   └── index.js
├── scss
│   └── main.scss
└── webpack.config.js
  • The app folder contains the html project and the javascript entry point file where you can import paradox.
  • The dist folder contains the built project and it's generated by webpack.
  • The node_modules folder contains the npm packages for the project.
  • The package.json file contains the project info and the npm scripts.
  • The package-lock.json file contains the npm packages info.
  • The server folder contains a simple Nodejs server that serves the dist folder and redirects all the requests to the index.html file.
  • The scss folder contains a simple main.scss and it should be compiled to dist/css/main.css.
  • The webpack.config.js file contains the webpack config.

Webpack config

const path = require("path");

module.exports = {
  entry: {
    "js/bundle": "./app/index.js",
  },
  target: "web",
  mode: "development",
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
          test: /\.(js)$/,
          exclude: /(node_modules|bower_components)/,
          use: {
              loader: 'babel-loader',
          }
      },
    ],
  },
  // ... other config
}

Paradox as a module in a simple HTML project

If you want to use it as a module in a simple HTML project, you should import it in your script like this:

<script type="module">
  import Paradox from "./path/to/penrose-paradox/build/index.js";
</script>

Documentation

Paradox includes the following features:

Build an element with Paradox.buildElement

Paradox provides a simple way to build an element with the buildElement function that takes the element name and an object with the element properties as arguments.

Properties:

Property Type Description
id string The element id
classList string The element class list separated by spaces
attributes object The element attributes (e.g. type, value, etc.)
events object The element events (e.g. click, change, etc.)
style object The element style (e.g. backgroundColor, color, etc.)
text string The element text
children array The element children
import Paradox from "penrose-paradox";

function handleButtonClick() {
  alert("Hello World!");
}

const myButton = {
  id: "myButton",
  classList: "btn btn-primary",
  attributes: {
    type: "button",
  },
  events: {
    click: handleButtonClick,
  },
  style: {
    backgroundColor: "red",
  },
  text: "Click me!",
  children: [
    {
      tag: "i",
      options: {
        id: "myButtonIcon",
        classList: "fas fa-hand-pointer",
      }
    },
  ],
}

document.body.appendChild(Paradox.buildElement("button", myButton));

NOTES:

  • The buildElement function will return a HTMLElement object.
  • The children property is an array of objects with the tag and options properties. The tag property is the element name and the options property is the object with the element properties.
  • The options property is optional, so you can pass just the tag property and it will return an element with no properties.

Routes with Paradox.Router

Paradox provides a simple router to handle the navigation between pages.

import Paradox from "penrose-paradox";

function Home(props) {
  const { root } = props;
  root.append(Paradox.buildElement("div", {
    id: "home",
    text: "Welcome to Paradox!",
  }));
}

function About(props) {
  const { name, root } = props;
  root.append(Paradox.buildElement("div", {
    id: "about",
    text: `Paradox is a simple vanilla javascript library for DOM manipulation. This is the ${name} page.`,
  }));
}

const root = document.getElementById("root");

const routes = [
  {
    path: "/",
    component: Home,
    props: {
      root,
    },
  },
  {
    path: "/about",
    component: About,
    props: {
      name: "About",
      root,
    },
  },
];

const router = new Paradox.Router(routes);
router.init()
  .then((path) => {
    console.info(`The current path is: ${path}`);
  })
  .catch((error) => {
    console.error(error);
  });

NOTES:

  • The router will look for the # in the url to handle the navigation. For example, if the url is http://localhost:8080/#/about, the router will navigate to the /about path.
  • The router will inject the props object into the component function as an argument and it will contain, besides the properties that you pass, the following properties:
    • queryString: A string with the query parameters. For example, if the url is http://localhost:8080/about?name=Paradox, the queryString will be ?name=Paradox.
    • params: An object with the path parameters. For example, if the url is http://localhost:8080/about/Paradox, and the path is /about/:name, the params object will be { name: "Paradox" }.
    • query: An object with the query parameters. For example, if the url is http://localhost:8080/about?name=Paradox, the query object will be { name: "Paradox" }.
    • baseUrl: A string with the base url. For example, if the url is http://localhost:8080/about?name=Paradox, the baseUrl will be http://localhost:8080.

PubSub with Paradox.pubsub

Paradox provides a simple PubSub implementation to handle the communication between components.

In case you're not familiar, PubSub is a popular messaging pattern in software architecture. It stands for Publish-Subscribe pattern and is used for communication between different parts of an application or between different applications.

In the PubSub pattern, publishers send messages without knowing who the subscribers are. Subscribers, on the other hand, express interest in one or more events and only receive messages that are of interest, without knowing who sent them.

This pattern is widely used in event-driven programming and can help to decouple the components of an application, leading to code that is easier to maintain and extend. In the context of Paradox, it allows components to communicate with each other in a decoupled manner.

import Paradox from "penrose-paradox";

Paradox.pubsub.subscribe("myEvent", (data) => {
  console.log(data);
});

Paradox.pubsub.publish("myEvent", "Hello World!");

NOTES:

  • You can use pubsub to communicate between components, for example, you can publish an event in a component and subscribe to it in another component. This way you can pass data between components without having to use props.
  • Subscriptions are not persistent, so if you subscribe to an event and then navigate to another page, the subscription will be lost.
  • You can use the Paradox.pubsub.unsubscribe method to unsubscribe from an event.
  • You can not publish an event before subscribing to it xd.

Examples

You can find some examples in the examples folder.

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Santiago Rincon - @alexsc6955

Roadmap

See the ROADMAP.md for a list of proposed features (and known issues).

If you have any ideas, please start a discussion and we can figure it out together.

Acknowledgements

  • K2 - For not letting me use React in their projects xd.