mercedui

1.2.9 • Public • Published

MercedUI

By Alex Merced of AlexMercedCoder.com

mui

If you prefer defining your components via classes, MercedElement is a base class easily building components: https://github.com/AlexMercedCoder/MercedElement

MercedUI has MercedElement built but if you only wanted the base class s you can use the smaller library above

About

The MercedUI Library creates some basic web components for assembling a userUI and some helper functions to help in creating a UI without having to increase your bundlesize by bringing a large UI library like Angular and React.

CDN Link: https://res.cloudinary.com/dithdroai/raw/upload/v1609694139/libraries/UI_gvselp.js (11kb)

CDN Link (ES 6 MODULE VERSION): https://res.cloudinary.com/dithdroai/raw/upload/v1609694139/libraries/MUIMODULE_q78isu.js (13 kb)

NPM

  • Webpack build generator npx create-mercedui-app projectName

  • library to create custom build npm install mercedui

Youtube Tutorials: https://www.youtube.com/playlist?list=PLY6oTPmKnKbYrP3DfCUTYYADu0IT9DRZZ

Installation

CDN

script src="https://res.cloudinary.com/dithdroai/raw/upload/v1609694139/libraries/UI_gvselp.js" charset="utf-8" defer></script>

NPM

npm i mercedui

in your javascript file

const {MercedElement, $m, $s, FormTool} = require("mercedui")

ES6 Module

index.html

<script type="module" src="app.js" charset="utf-8" defer></script>

app.js

import {MercedElement, $m, $s, FormTool} from "https://res.cloudinary.com/dithdroai/raw/upload/v1609694139/libraries/MUIMODULE_q78isu.js"

Classes

SiteBuilder

A class to encapsulate reactive data and templates

The constructor takes three arguments:

  • DOM element to apply template to (assigns template to innerHTML)
  • store, reactive data, most useful as an object with properties
  • builder, a function that takes the store as an argument and returns a template string
const target = document.getElementById('test');
const builder = (store) => {
    return `<h1>${store.hello}</h1>`;
};

const test = new SiteBuilder(target, { hello: 'Hello World' }, builder);

SiteBuilder has one method, updateData, which takes one argument which becomes the new store and triggers a re-rendering of the template.

const goodbye = () => {
    test.updateStore({ hello: 'goodbye' });
};

FormTool

This is a class whose constructor takes a form element and allows you to grab the form data and clear the form with each.

this.grabValues() returns object with form values with name property as keys

this.clearForm() clears all form Values

this.fillFields(object) takes object fills in the form fields where key matches input name property

const form = document.querySelector('form');

const testForm = new FormTool(form);
<form id="myform">
    <input type="text" name="one" />
    <input type="text" name="two" />
    <input type="text" name="three" />
    <textarea name="four"></textarea>
</form>
<button onclick="console.log(testForm.grabValues())">Form Data</button>
<button onclick="testForm.clearForm()">Clear Values</button>

FormTool has two methods, grabValues() which will return you an object with the forms values using the name property as the key and the value property as the value. The second method is clearForm which will render the property of value of all form elements to null. Won't grab or clear the value on submit inputs but will for all others.

MercedElement

MercedElement is a base class for creating components. In the constructor use the super to define the template builder function, state, and reducer. Afterwards use the MercedElement.makeTag(name, class) static function to register the HTML tag

class TestTest extends MercedElement {
    constructor() {
        super(
            (state, props) => { // Argument 1: The Build Function
                return `<h1>${state.hello}</h1><h2>${props.user}</h2>`;
            },

            { hello: 'Hello World' }, //Argument 2: The Initial State

            (oldstate, payload) => { //Argument 3: Reducer Function (think redux)
                if (payload.action === 'goodbye') {
                    return { hello: 'goodbye' };
                }
            }
        );
    }
}

MercedElement.makeTag('test-test', TestTest);

in HTML

<test-test user="joe"></test-test>

Instance methods

instance.build() - captures the current props and state and renders a template

instance.setState(newState) - updates the components state and runs build

instance.dispatch(payload) - updates the state by running the reducer defined in the constructor

Static methods

MercedElement.gRegister(classInstance) - registers a component instance with the global state

MercedElement.clearRegister() - removes all components from global registry

MercedElement.gSetState(newState) - set the global state and re-render all registered components

MercedElement.gDispatch(reducer, payload) - update the global state with the given reducer function and payload, then re-render all registered components

MercedElement.makeTag(name, class) - register your custom components with HTML tags, the name must have a dash like ('hello-world')

LifeCycle Functions

Outside the constructor just override the same functions used in the native web components api.

connectedCallback(){} => Runs when components mounted

disconnectedCallback(){} => Runs when component is removed from dom

postBuild(state, props){} => runs after every render completes

read JavaScript Documentation regarding adoptedCallback and attributeChangedCallback

Functions

getQueryHash

getQueryHash() This function will return an array, the first element being an object with all URL queries, the second being any URL hashes that may exist.

const [queries, hash] = getQueryHash()

MUIRequest

MUIRequest(url, configObject) This is a really simple abstraction over the fetch API, just helps you skip the stop of having to turn your response back into an object. The goal was just to save you the trouble of loading other AJAX libraries like Axios to keep your bundleSize small.

MUIRequest('https://jsonplaceholder.typicode.com/posts/1').then((response) =>
    console.log(response)
);

makeComponent

makeComponent({options}) Pass an object with all the options in to generate a component. This is best used for a very simple components. For multi-line templating and reactive state use makeLiveComponent, MercedElement, or quickComponent

Option properties

  • prefix: the first part of the components components name
  • name: the second part of the components name
  • template: a string with the html to be outputted whenever the tag is used (entire string must be on one line)
  • connected: string for code to be run when the component is mounted
  • observe: string to ObservedAttributes to constructor
  • other: string to define methods or make use of attributeChangedCallback, disconnectedCallback or adoptedCallback
  • debug: If set to true, will console log the underlying string that is evaluated to create the component so you can debug your component.

Defining a component

makeComponent({
    prefix: 'test',
    name: 'comp',
    template: '<h1>Hello World</h1>'
});

using the component

<test-comp></test-comp>

makeLiveComponent

makeLiveComponent({options}) Pass an object with all the options in to generate a component with reactive data.

Option properties

  • prefix: the first part of the components components name
  • name: the second part of the components name
  • builder: function that is passed the store object and rendered to dom
  • store: Object with data the template depends on, initially passed in as a string
  • connected: string for code to be run when the component is mounted
  • observe: string to ObservedAttributes to constructor
  • other: string to define methods or make use of attributeChangedCallback, disconnectedCallback or adoptedCallback
  • debug: If set to true, will console log the underlying string that is evaluated to create the component so you can debug your component.

Defining a component

const builder = (store) => {
    return `<h1>${store.hello}</h1>`;
};

makeLiveComponent({
    prefix: 'test',
    name: 'life',
    builder,
    store: `{ hello: 'Hello World' }`
});

using the component

<test-life></test-life>

The way this works is an instance of the SiteBuilder class is in the properties of the element, so if you need to update the store just use the function this.life.updateStore({newstore}) and it will update the store and re-render the template.

captureProps

captureProps(element) Pass in any html element and this function returns all of its properties as an object.

globalStore

creates a global store object with three functions NOTE: You can only register SiteBuilder objects and components made with the makeLiveComponent function for this to work. You can create registerable custom objects as long as the object has "life" property that is a SiteBuilder object.

const myStore = globalStore({ hello: '' }); //Creates the global store Object

myStore.get() //returns the current store

myStore.register(document.querySelector('my-component')) //add component to store register

myStore.set({hello: "hello world"}) //updates store, passes store to all registered components and re-renders them

myStore.clearRegister() // Clears Component Registry

gsReducer

This allows you to bind a globalStore to a reducer function, returns a function that takes a payload which is passed into the reducer function setting the bound globalStore to the return value.

Creating a reducer

const reduceMyStore = gsReducer(myStore, (oldStore, payload) => {
    switch (payload.action) {
        case 'test':
            oldStore.hello += 'o';
            return { ...oldStore };
            break;

        default:
            return { ...oldstore };
            break;
    }
});

using gsReducer

<button onclick="reduceMyStore({action: 'test'})">Add o</button>

mapToDom

mapToDom(array, mapFunction, targetElement) Takes an array, maps a function that returns a string over its elements concatenating all the returned strings replacing the innerHTML of the target element. If you plan on re-rendering this data regularly you may prefer to use the bindData function.

const myData = ['hello', 'goodbye', 'farewell'];

const container = document.getElementById('container');

mapToDom(
    myData,
    (value, index) => {
        return `
  <merced-card theBorder="3px solid black">${value} is at index ${index}</merced-card>
  `;
    },
    container
);

bindData

bindData(arr, mapFunction, targetElement) This function is a wrapper around mapToDom, it returns a function to change the array data and then re-run the mapToDom function to auto re-render when the data changes using the returned function.

const myData = ['hello', 'goodbye', 'farewell'];

const container = document.getElementById('container');

const updateCards = bindData(
    myData,
    (value, index) => {
        return `
  <merced-card theBorder="3px solid black">${value} is at index ${index}</merced-card>
  `;
    },
    container
);

const addOne = () => {
    myData.push('one');
    updateCards(myData);
};

createRotator

createRotator(object, elementToRenderTo) Pass in an object where each property is a string of html and the dom element to connect to. It returns a function that will allow you to rotate between these properties.

createBuildRotator works the same way but instead of templates the object should be made up of builder functions, and a second argument should passed to the rotator with a store object with any data used for rendering.

createCompRotator only takes one argument (elementToRenderTo) and returns as functions that takes two arguments, first being a string with the name of the component to render and string with attributes to add to the component.

const rotator = document.getElementById('rot')

const rotations = {
  first: `<h1>Hello World</h1>`,
  second: `<h1>Hello World 2</h1>`,
  third: `<h1>Hello World 3</h1>`
}

const rotate = createRotator(rotations, rotator)
<div id="rot"></div>
<button onclick="rotate('first')">First</button>
<button onclick="rotate('second')">Second</button>
<button onclick="rotate('third')">Third</button>

mapToString

mapToString(array, mapFunction) Takes an array, maps a function that returns a string over its elements concatenating all the returned strings and returns the resulting string. This is particularly useful for generating strings to be used in your rotator properties.

simpleComponent

Function for creating a web component that is useable in your html.

simpleComponent(config)

The config object has many properties to help build your component: prefix = the prefix to your tag tag name = the name of your component (the html tag name would be prefix-name) builder = function that returns template (state, props) => {return templateString} state = initial state object connected = pass in a string with your connectedCallback function connectedCallback(){stuff to happen when component mounted} disconnected = pass in a string with your disconnectedCallback function disconnectedCallback(){stuff to happen when component unmounted} observe: pass in string with ObservedAttributes function for component constructor other: string to define other methods and/or define attributeChangedCallback/adoptedCallback debug: If set to true, will console log the underlying string that is evaluated to create the component so you can debug your component. postBuild: (state, props) => function that runs after each render

Defining a component


simpleComponent({
    prefix: 'test',
    name: 'test',
    builder: (state, props) => {
        return `<h1>${state.hello}</h1>
    <h2> ${props.user} </h2>`;
    },
    state: { hello: 'hello world' }
});

const comps = document.querySelectorAll('test-test');

using components in your HTML

In the below code we see the component used three times with different props along with three button that update each components state.

<test-test user="jones"></test-test>
<test-test user="harry"></test-test>
<test-test user="james"></test-test>
<button onclick="comps[0].setState({hello: 'one'})">One</button>
<button onclick="comps[1].setState({hello: 'two'})">Two</button>
<button onclick="comps[2].setState({hello: 'three'})">Three</button>

quickComponent

quickComponent is a function to help quickly make a component using the MercedElement class. You are better of using the MercedElement class to make your components if you need to add addtional class methods or use the adoptedCallback or attributeChangedCallback.

quickComponent(name, builder, state, reducer, connected, disconnected)

  • name => the name of component must have a dash like "my-component"
  • builder => function that returns html template string
  • state => initial state object, like any MercedElement can be updated via instance.setState(newState)
  • reducer => function that runs when use instance.dispatch(payload), function is passed the oldState and payload and its return value becomes the new state.
  • connected(element) => function that is passed the element runs on component mounting
  • disconnected(element) => function that is passed the element and runs when function is dismounted
Building a Component with QuickComponent
const builder = (state, props) => {
    return `<h1>${state.hello}</h1>
          <h2>${props.user}</h2>`;
};

initialState = { hello: 'hello world' };

const connected = (element) => {
    console.log(element);
};

quickComponent('test-test', builder, initialState, null, connected);

The component in your HTMLElement

<test-test user="Joe"></test-test>

$M DOM function abbreviations

abbreviations of standard DOM functions to make using them easier

$m.select(query) => document.querySelector(query)

$m.selectAll(query) => document.querySelectorAll(query)

$m.byId(query) => document.getElementById(query)

$m.byTag(query) => document.getElementsByTagName(query)

$m.byClass(query) => document.getElementsByClassName(query)

$m.create(query) => document.createElement(query)

$m.remove(query) => document.removeChild(query)

$m.append(query) => document.appendChild(query)

$m.replace(old, new) => document.replaceChild(old, new)

$S ShadowDOM function abbreviations

abbreviations of shadow DOM functions to make using them easier

$s.select(element, query) => element.shadowRoot.querySelector(query)

$s.selectAll(element, query) => element.shadowRoot.querySelectorAll(query)

$s.byId(element, query) => element.shadowRoot.getElementById(query)

$s.byTag(element, query) => element.shadowRoot.getElementsByTagName(query)

$s.byClass(element, query) => element.shadowRoot.getElementsByClassName(query)

$s.create(element, query) => element.shadowRoot.createElement(query)

$s.remove(element, query) => element.shadowRoot.removeChild(query)

$s.append(element, query) => element.shadowRoot.appendChild(query)

$s.replace(element, old, new) => element.shadowRoot.replaceChild(old, new)

Components

m-router and m-link

Very similar to most routers, the router tag specifies where links will render and link creates a link that when clicked will render a particular component to the router with the same name attribute. Each router must have a unique name attribute.

  • routers have a default attribute to specify a component to start with
  • links have a target attribute to specify what component will be rendered if clicked.

Given these two Components

makeLiveComponent({
    prefix: 'hello',
    name: 'world',
    store: '{hello: ""}',
    builder: (store) => {
        const props = captureProps(this);
        return `<h1>Hello World</h1>`;
    }
});

makeLiveComponent({
    prefix: 'goodbye',
    name: 'world',
    store: '{hello: ""}',
    builder: (store) => {
        const props = captureProps(this);
        return `<h1>Goodbye World</h1>`;
    }
});

Here is an example of using the router and link tags

<m-router name="main" default="hello-world" props="user='steve'"></m-router>
<m-link name="main" target="goodbye-world" props="user='steve'">
    Click Me to Say Goodbye
</m-link>

All Components below have a instance.toggle() method to toggle the display of the component

MercedContainer

This has been removed from the main CDN, to use this components use this CDN link: http://www.alexmercedcoder.com/UI2.js


<merced-container></merced-container>

creates a div with the following default styles:


display: flex;
width: 90%;
flex-wrap: wrap;
margin: 20px auto;

can pass in the following properties:

  • justify: sets the justify-content style property
  • align: sets the align-items style property
  • height: sets the height style property

MercedCard

This has been removed from the main CDN, to use this components use this CDN link: http://www.alexmercedcoder.com/UI2.js


<merced-card></merced-card>

creates a div with the following default styles:


display: flex;
width: 300px;
flex-direction: column;
flex-wrap: wrap;
margin: 20px auto;

can pass in the following properties:

  • justify: sets the justify-content style property
  • align: sets the align-items style property
  • height: sets the height style property
  • theBorder: sets the border style property

Readme

Keywords

none

Package Sidebar

Install

npm i mercedui

Weekly Downloads

0

Version

1.2.9

License

ISC

Unpacked Size

68.1 kB

Total Files

10

Last publish

Collaborators

  • alexmerced