Why Mk[ui] ?

  1. Independent of any 3rd party libraries/frameworks (including jQuery).
  2. Supports AMD, CommonJS, and vanilla JavaScript.
  3. Plays nice with Angular and React.
  4. Easily customizable JavaScript, CSS (both LESS and SCSS versions), and Markup for any component.
  5. Written with responsive design and full WCAG 2.0 accessibility support.
  6. Written with full mobile and tablet support (and their screen readers) for the best user experience possible.

What is Mk[ui] ?

Mk[ui] is a flexible ES5 library build with WCAG 2.0 accessiblity, mobility, and responsive design at the forefront. All of our components follow the W3 guidlines on accessibility. We also accurately mimic native browser controls for the best user experience possible. With mobile, we degrate to triggering device controls when applicable, again, for the best user experience possible. All components support AMD module loading, play nicely with frameoworks like Angular, and insert DOM nodes into descrete "root" elements for compatibility with frameworks like React and the Virtual DOM. All components advocate HTML5, CSS3, and come with both LESS and SASS alternatives depending on what you need for your project.

At the base, each components inherits from Core, which is basically just an abstract object bundled with a bunch of goodies. Components derived directly from core are called 1st Class components. Components derived from 1st Class components are called 2nd Class components. And so on. Below we outline the different features of Core available to you, whether using an existing component or building your own.

Create

Want to create your own Mk objects? Use Mk.create for that. Create takes up to three arguments: a name, a base class (optional), and a prototype. Note that as of now, the base class must always be derived from Mk. We may change this later.

//
// create a first class object (inherits from Mk Core)
// namespaced as myClient.myObject.
var myObject = Mk.create("myClient.myObject", {
	...prototype goes here...
});
//
// create a second class object derived from Selectmenu.
var myObject = Mk.create("myClient.myObject", Mk.Selectmenu, {
	...prototype goes here...
});

Define

We can also store random data within Mk using the *define* method. When using create, define is called internally, storing the object as the *name* argument.

// store this random array of data
Mk.define("myClient.availableStates", [
	"Colorado",
	"California",
	"New York",
	"Washington"
]);

Get

Using the code in the Create section above we can also retrieve our components with the *get* method. This is a safer way to retrieve our objects rather than raw object pointing.

// get the selectmenu object
var Selectmenu = Mk.get("Selectmenu");
//
// get the myClient.myObject object
var myObject = Mk.get("myClient.myObject");
//
// get the myClient.availableStates object
var states = Mk.get("myClient.availableStates");

Type Checking

Type checking is pretty important in JavaScript and unfortunately the typeof function doesn't really provide us with a great deal of awesome. Fortunately we've created a light-weight addition to type checking accessibly on Mk as a static member. All types typeof uses are still available through the use of Mk.type.

//
// checks for type array
Mk.type(o, "array")
//
// checks for type array-like
// this could be an array, jQuery, html collection, arguments, etc.
Mk.type(o, "arraylike");
//
// checks for truthy/falsey
Mk.type(o, "empty");
//
// check for null
Mk.type(o, "null");
//
// check for a date object
Mk.type(o, "date");
//
// checks for type nodelist
Mk.type(o, "nodelist")
//
// checks for type node
Mk.type(o, "node");
//
// checks for type window
Mk.type(o, "window");
//
// check if o is a function but NOT a classlike object.
Mk.type(o, "function");
//
// check if o is a classlike object
Mk.type(o, "classlike");
//
// check if o is an instance of an object
Mk.type(o, "instance");
//
// check if o is a descriptor (see Object.defineProperty)
Mk.type(o, "descriptor");

You can also combine types with a pipe.

Mk.type(o, "string|number|undefined|arraylike|classlike");

Template System

Mk[ui] comes with a light-weight templating system similar to handlebars. The template system is accessed with methods like template(), format(), and html() on the prototype of Core. You can also access the templating system yourself as it lives as a static property on Mk (Mk.fn.template). You may pass in template string directly or pass in reference keys while keeping the actual define templates in an organized place (templates and formats property on the Core prototype for instance). Below is a list of the Template Engine features and how to use them.

Template Keys

Every template has a key accessible with $key. For instance, if you're using the Selectmenu, the key is mk-sm which gets prepended to all of the element class names.

<div class="{{$key}}-shadow">

Accessing Data

To access template data, use double curly braces to tell the template engine the data point you'd like to access based off of it's current scope.

<div>{{datapoint}}</div>

Changing Scope

It's more than likely your data will have multi-dimentions. You can access "deep" objects with the scope keyword. For instance, let's say our data object has a property called list, which has a property called items we want to access.

{{scope:list}}
	<div>{{items}}</div>
{{/scope:list}}

Nesting Templates

You can call templates within templates like the below. If you reference a template that does not exists, no markup will be generated. To reference templates accurately, make sure it exists in the template object you pass to the parser.

<div class="{{$key}}-shadow">
	{{template:my-template-name}}
</div>

Looping

The best part of templating by far. You can loop objects, arra-like object, and even a simple integer. No matter how you loop, you'll have access to a secret data point called $index which represents the iteration count. When looping arrays, each iteration will change the scope of the data to that data set.

{{loop:options}}
	<option data-number="{{$index}}" value="{{value}}">{{label}}</option>
{{/loop:options}}

Looping an object will give you key, value pairs. If you loop an array who's items are NOT objects/arrays, you'll also be given a key, value pair object. For instance, you loop [1,2,3,4,5] your value will be the integer and key will be empty.

{{loop:myObject}}
	<option data-number="{{$index}}" value="{{value}}">{{key}}</option>
{{/loop:myObject}}

You can also loop a number, which keeps the same data context running a standard for loop on the size of the number provided. This is really handy for presentational UI elements.

{{loop:10}}
	<option value="{{$index}}">Options Number {{$index}}</option>
{{/loop:10}}

If Statements

Mk Templating Engine if statements are basic. Basically they only interpret truthy/falsey statements. So no, no crazy logic is supported here. The only exception to the truthy/falsey is the value 0. Mk does not consider 0 to be falsey and will evaluate it as truthy. Null, undefined, empty string, and false will all evaluate to falsey.

{{loop:options}}
	<option data-number="{{$index}}" value="{{value}}">
		{{label}}
		{{if:description}}
			<span class="{{$key}}-description">{{description}}</span>
		{{/if:description}}
	</option>
{{/loop:options}}

Super Functions & Inheritance

JavaScript is a bit restrictive when it comes to inheritance. Thankfully with ES5 we have a ton of new features that allowed us to create Super Functions. All component methods are passed through a property scrubber, which supports property descriptors and sets up a call-stack to track the chain of invoked methods. When taking advantage of the Mk inheritance, each time a method is invoked, that method has access to a 'super' property on each Mk instance. The super property is firstly a property getter, which will return you the super class method of the same named method. You may then invoke that super method, which calls the function is proper context. Super invoking is recursive, so it's possible to continue calling super functions all the way down to the base object (Core). Since we've provided access to the Mk inheritance as static methods on the Mk object, you can take advantage of using the Mk inheritance on existing object or when creating your own objects.

var myObject = Mk.create('MyObject', {
	_init: function (root, config) {
		//we inherited from Mk so call the superclass _init method
		this.super(root, config);
	}
});
//
//copy an entire object of members
//this will accurately set existing property descriptors,
//setup super functions, and create new property descriptors using the Mk.property method below.
Mk.inherit(myObject.prototype, objectToInheritFrom);
//
//set a new function onto the myobject prototype
Mk.property(myObject.prototype, 'newMethod', function () {
	//do stuff...
});
//
//set a property descriptor getter only
Mk.property(myObject.prototype, 'newProperty', {
	configurable: true,
	enumberable: true,
	get: function () {
		return this.newMethod();
	},
	set: null
});

Animation & Transition Effects

Animations are taken care of with CSS3 but the JavaScript end does contain animation event handlers to invoke perticular behaviors when elements have completed animations. You also have control over turning animations on or off through the JavaScript Mk API.

// enable transitions
Mk.transitions.enable();
//
// disable transitions
Mk.transitions.disable();
//
// get the transition event name
Mk.transitions.key;
//
// booleans representing transitions enabled
Mk.transitions.enabled;
//
// booleans representing transitions disabled
Mk.transitions.disabled;

Event Emitters

With Mk 2.0 you no longer hook into behaviors through DOM events. We now use an event emitter to call custom functionality. This has a few benefits. First, DOM event listeners are kept at a minimum. Second, we can add hooks to just about every behavior possibly, making our components extremely flexible and versitile. Events are specific to each component, so there will be no example here but know that each component built with Mk has an on(), one(), off(), and emit() method used for event hooks.

API

Below are the different public properties and methods accessible to you, the end developer. All of these are accessible on your Core instance as well as inside event handlers bound to your instance. Some methods have intentionally been left out due to their difficulty tof use for end developers vs. internal use.

Methods

  • instance.$(selector, context)

    Custom Mk DOM manipulation wrapper. Think minimalistic jQuery.

    Parameters
    • Name
      selector
      Type
      Mixed - String/Node/NodeList/Wrapper
      Description
      A selector, Node, NodeList, or wrapped ($) node.
    • Name
      context
      Type
      Mixed - String/Node/Wrapper
      Description
      A parent selector, node, or wrapped ($) node.
  • instance.uid()

    Generates a unique id.

    • No params required.
  • instance.template(name, data)

    Invokes the Template Engine using the configured tempates and returns parse string.

    Parameters
    • Name
      name
      Type
      String
      Description
      Name of the template.
    • Name
      data
      Type
      Object
      Description
      Data Object given to template parser.
  • instance.format(name, data)

    Invokes the Template Engine using the configured formats and returns parse string.

    Parameters
    • Name
      name
      Type
      String
      Description
      Name of the format.
    • Name
      data
      Type
      Object
      Description
      Data Object given to format parser.
  • instance.html(template, data)

    Invokes the Template Engine using the configured templates and returns a wrapped ($) Node/DocumentFragment.

    Parameters
    • Name
      name
      Type
      String
      Description
      Name of the template.
    • Name
      data
      Type
      Object
      Description
      Data Object given to template parser.
  • instance.each(who, fn)

    Loops objects and array-like objects running a function on each iteration. Return false to break loop. Return -1 to splice/delete item from object.

    Parameters
    • Name
      who
      Type
      Mixed
      Description
      Object or Array-like object to iterate over.
    • Name
      fn
      Type
      Function
      Description
      Callback function run on each iteration.
  • instance.first(who, fn)

    Loops objects and array-like objects running a function on each iteration. The first value to be returned will stop loop and assign from callback.

    Parameters
    • Name
      who
      Type
      Mixed
      Description
      Object or Array-like object to iterate over.
    • Name
      fn
      Type
      Function
      Description
      Callback function run on each iteration.
  • instance.map(who, fn)

    Loop objects and array-like objects and return a value on each iteraction to be 'mapped' to a new object (like Array's map). Return nothing, or undefined, to exclude adding anything for that iteration.

    Parameters
    • Name
      who
      Type
      Mixed
      Description
      Object or Array-like object to iterate over.
    • Name
      fn
      Type
      Function
      Description
      Callback function run on each iteration.
  • instance.filter(who, fn)

    Loop objects and array-like objects and return true or false to specify whether to filter the element out of the new return object. (like Array's filter).

    Parameters
    • Name
      who
      Type
      Mixed
      Description
      Object or Array-like object to iterate over.
    • Name
      fn
      Type
      Function
      Description
      Callback function run on each iteration.
  • instance.node(selector[, context])

    Shadow nodes created by Mk components have prefixed names. This method runs your selector through the prefixed name and root context to easily find your element.

    Parameters
    • Name
      selector
      Type
      String
      Description
      A selector to be run through the selector() prefixer.
    • Name
      context
      Type
      Mixed
      Description
      Selector/Node/Wrapped ($) Node to be used as context element. Default is root.
  • instance.selector(name)

    Takes a base string selector (ie: 'list') and returns the component's true selector (ie: mk-core-list).

    Parameters
    • Name
      key
      Type
      String
      Description
      A selector to be prefixed with component naming.
  • instance.transition(node, handler)

    Binds transition event to a node(s). If transitions are disabled, or not supported, handler is executed in setTimeout (1 millisecond).

    Parameters
    • Name
      node
      Type
      Mixed
      Description
      A Selector/Node/Wrapped ($) Node to bind transition event handler on.
    • Name
      handler
      Type
      Function
      Description
      Event handler to be bound.
  • instance.clearTransitions(node)

    Clear transition handlers on node.

    Parameters
    • Name
      node
      Type
      Mixed
      Description
      A Selector/Node/Wrapped ($) Node to bind transition event handler on.
  • instance.delay(fn[, milliseconds])

    Runs a timer on invoking a function. Useful for rendering race conditions and transition effects. For rendering race conditions, no milliseconds are necessary as the default (1) handles that.

    Parameters
    • Name
      fn
      Type
      Function
      Description
      Function to be invoked when delay ends.
    • Name
      milliseconds
      Type
      Number
      Description
      Number of milliseconds for the timer. Default is 1.
  • instance.on(event, handler)

    Binds a handler to an event type through the Event Emitter. Allows for namespaced events.

    Parameters
    • Name
      event
      Type
      String
      Description
      Event type
    • Name
      handler
      Type
      Function
      Description
      Handler to invoke when event type has been emit.
  • instance.one(event, handler)

    Binds a handler to an event type through the Event Emitter. Once fired, an event bound through one() will be removed. Allows for namespaced events.

    Parameters
    • Name
      event
      Type
      String
      Description
      Event type
    • Name
      handler
      Type
      Function
      Description
      Handler to invoke when event type has been emit.
  • instance.off(event[, handler])

    Removes a handler (or all handlers) from an event type.

    Parameters
    • Name
      event
      Type
      String
      Description
      Event type
    • Name
      handler
      Type
      Function
      Description
      Optional handler to remove. Defaults to remove all handlers for event type.
  • instance.emit(event[, argument1, arguments2, ...])

    Invokes handler(s) bound to event type.

    Parameters
    • Name
      event
      Type
      String
      Description
      Event type
    • Name
      arguments
      Type
      Mixed
      Description
      Any other arguments passed through emit will be applied to the handlers invoked on the event.
  • instance.init(root[, config])

    Internal, private, method used as a contructor. Useful when building your own custom components. Invoked internally only.

    Parameters
    • Name
      root
      Type
      Mixed
      Description
      A Selector/Node/Wrapped ($) Node set to be the root.
    • Name
      config
      Type
      Object
      Description
      Configuration object passed into an instance as settings.
  • instance.define(root[, config])

    A setup function called by _init. This initializes the root, events, config object, formats, templates, etc. Invoked internally only.

    Parameters
    • Name
      root
      Type
      Mixed
      Description
      A Selector/Node/Wrapped ($) Node set to be the root.
    • Name
      config
      Type
      Object
      Description
      Configuration object passed into an instance as settings.
  • instance.configure(object)

    Internal method, invoked by _init, responsible for setting object properties onto the internal configuration object.

    Parameters
    • Name
      object
      Type
      Object
      Description
      An object of end developer settings passed in and added to the config property.
  • instance.param(name, type, config, default[, node])

    Runs logic to find a configuration setting. It will first look to see if the value lives on config already. If not, it will check for the value on the node (or root if no node is specified). Lastly, it will type case the value based on the type specified. The final result will be set on the config object passed in.

    Parameters
    • Name
      name
      Type
      String
      Description
      Name of config property.
    • Name
      type
      Type
      String
      Description
      Type to case value to.
    • Name
      config
      Type
      Object
      Description
      Object to set result value on.
    • Name
      default
      Type
      Mixed
      Description
      Default value to set if no value is found through all other means.
    • Name
      node
      Type
      Wrapped Node ($)
      Description
      Optional Node to search for configurations on. Default is root.
  • instance.bind()

    Internal Placeholder method for binding the event handlers. Invoked internally by init.

    • No params required.
  • instance.build()

    Internal Placeholder method for building the components. Invoked internally by init.

    • No params required.
  • instance.mount()

    Internal Placeholder method for mounting the component to the DOM. Invoked internally by init.

    • No params required.
  • instance.unmount()

    Internal Placeholder method for component teardown. Invoked by end developer by choice.

    • No params required.

Properties

  • instance.name

    Unique name used for each object derived from Mk. This name will be used in templating signatures, markup, event emitters, and selectors.

  • instance.templates

    Contains default templates for generating markup. See the Templates section for more details.

  • instance.formats

    Contains default formats for text. See the Templates section for more details.

  • instance.config

    Configuration object of settings built of attributes and parameters passed into each instance.

  • instance.events

    Event Emitter handlers are stored here.

  • instance.root

    The root elements passed in as the first parameter to each instance of an Mk object.

  • instance.deviceExp

    Expression used to check the user agent for device patterns.

  • instance.super

    The super is a property as well as a function. It is dynamic in that it will return you the same super method as derived method you are invoking, but in correct context. Super is also recursive and can be chained down until you reach the Core object, Mk.

  • instance.keycode

    Object containing friendly named keycodes for keyboard events.

  • instance.transitions

    Boolean representing if transitions are turned on or not.

  • instance.version

    Current version.

  • instance.element

    The root as a raw Node.

  • instance.device

    Returns device API. See Device for more details.

  • instance.devicekey

    Key pulled from user agent for general device name checking (iphone, android, ipad, etc).