@instawork/design-system
Version:
The design system for Instawork's web apps
129 lines • 4.55 kB
JavaScript
import * as $ from 'jquery';
const DATA_CONTROLLER = 'iw-component';
const CUSTOM_COMPONENT_ATTR = 'iw-component';
const CUSTOM_COMPONENT_SELECTOR = `[${CUSTOM_COMPONENT_ATTR}]`;
let instanceId = 0;
function getIwControllerFn(ctrlClass) {
return function getIwController() {
return ctrlClass.getController(this.filter(CUSTOM_COMPONENT_SELECTOR).add(this.find(CUSTOM_COMPONENT_SELECTOR)));
};
}
/**
* A base class that handles shared functionality for custom components
*/
export class CustomComponent {
constructor($el) {
this.$el = $el;
/**
* The JQuery-wrapped component host element
* @type {JQuery}
*/
this.$el = $el;
/**
* The native host element
* @type {HTMLElement}
*/
this.el = $el[0];
this.idPrefix = this.constructor.ID_PREFIX;
this.id = this.$el.prop('id') || `${this.idPrefix}--${instanceId++}`;
this.$el
.prop('id', this.id)
.attr(CUSTOM_COMPONENT_ATTR, '')
.data(DATA_CONTROLLER, this);
if (this.constructor.TEMPLATE) {
this.$el.html(this.constructor.TEMPLATE);
}
}
/**
* Extend jQuery with the component's jQuery plugin function.
*/
static loadPlugin() {
if (!$.fn.getIwController) {
$.fn.getIwController = CustomComponent.jQueryComponentControllerFn();
}
}
static get ID_PREFIX() { return this.getIdPrefix(); }
static getIdPrefix() {
return this.COMPONENT_SELECTOR;
}
static getController($el) {
return $el.data(DATA_CONTROLLER);
}
static bind($el) {
return this.getController($el) || new this($el);
}
static jQueryPlugin(controllerName, extras, preInit) {
return Object.assign(this.jQueryInitFn(preInit), {
[controllerName]: this,
COMPONENT_SELECTOR: this.COMPONENT_SELECTOR,
CUSTOM_COMPONENT_ATTR: this.CUSTOM_COMPONENT_ATTR,
CUSTOM_COMPONENT_SELECTOR: this.CUSTOM_COMPONENT_SELECTOR,
}, extras);
}
/**
* Returns a function that can act as an initializer for the component
*/
static jQueryInitFn(preInit) {
const ctrlClass = this;
return function initCustomComponent() {
if (typeof preInit === 'function') {
preInit.call(this);
}
return this.filter(ctrlClass.COMPONENT_SELECTOR)
.add(this.find(ctrlClass.COMPONENT_SELECTOR))
.each((index, el) => { ctrlClass.bind($(el)); });
};
}
static jQueryComponentControllerFn() {
return getIwControllerFn(this);
}
/**
* Returns a CSS selector style string with the tag name and ID representing the component host element.
*
* Example: iw-component#some-id--1
*/
getDebugIdentifier() {
return this.getDebugIdentifierById();
}
getDebugIdentifierById() {
const tag = this.$el.prop('tagName').toLocaleLowerCase();
const id = this.$el.attr('id');
return `${tag}#${id}`;
}
attributeError(attributeName, message, required = false) {
return Object.assign(new Error(`The ${required ? "required " : ""}"${attributeName}" attribute on element "${this.getDebugIdentifier()}" ${message}`), {
name: 'AttributeError',
attributeName,
attributeRequired: false,
element: this.el,
});
}
attributeInvalidError(attributeName, reason, value) {
return Object.assign(this.attributeError(attributeName, `is invalid: ${reason}`), {
name: 'AttributeInvalidError',
reason,
value,
});
}
requiredAttributeError(attributeName) {
return Object.assign(this.attributeError(attributeName, 'is missing', true), {
name: 'AttributeRequiredError',
required: true,
});
}
}
CustomComponent.CUSTOM_COMPONENT_ATTR = CUSTOM_COMPONENT_SELECTOR;
/**
* Returns a selector string that can be used to find elements bound to a {@link CustomComponent} instance.
*
* The iw-component attribute is automatically added to any component using {@link CustomComponent} so they
* can be easily identified.
*/
CustomComponent.CUSTOM_COMPONENT_SELECTOR = CUSTOM_COMPONENT_SELECTOR;
/**
* Overridden to return a CSS selector for the host element of the component.
*
* @abstract
*/
CustomComponent.COMPONENT_SELECTOR = '';
//# sourceMappingURL=custom-component.js.map