UNPKG

render-component

Version:

A base web component to write functional web components. Combined with a virtual dom library this component removes all the boilerplate from your components.

183 lines (156 loc) 8.08 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Peforms: (de)serialization, observed properties and automatic rendering (in animationframe) /* Attributes to properties */ // Assumes property names as fooBar and attribute names as foo-bar and maps them accordingly // Inspired by: https://github.com/elix/elix/blob/master/mixins/AttributeMarshallingMixin.js var deserialize = { bool: function bool(val) { if (val === true || val == 'true') return true; if (val === false || val == 'false') return false; return null; }, string: function string(val) { return val + ""; }, func: function func(val) { if (typeof val === 'function') return val; if (typeof val === 'string') { if (window[val]) return window[val]; return new Function(val); } return null; }, object: function object(val) { if ((typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object') return val; return null; // TODO try JSON.deserialize }, array: function array(val) { if (Array.isArray(val)) return val; throw 'not implemented'; }, date: function date(val) { if (val instanceof window.Date) return val; throw 'not implemented'; }, number: function number(val) { var val = Number(val); if (isNaN(val)) return null; return val; }, any: function any(val) { return val; } }; var defaultValues = { bool: true, string: '', func: function func() {}, object: {}, array: [], date: null, number: 0, any: '' }; var RenderComponent = function (_HTMLElement) { _inherits(RenderComponent, _HTMLElement); function RenderComponent() { _classCallCheck(this, RenderComponent); // Create a (private) properties object with custom getter/setter var _this = _possibleConstructorReturn(this, (RenderComponent.__proto__ || Object.getPrototypeOf(RenderComponent)).call(this)); var observedAttributes = []; Object.keys(_this.constructor.properties).forEach(function (key) { var backingProperty = Symbol(key); Object.defineProperty(_this, key, { get: function get() { return this[backingProperty]; }, set: function set(val) { if (deserialize[this.constructor.properties[key].type]) { val = deserialize[this.constructor.properties[key].type](val); if (val === null) return; } //if(this[backingProperty] === val) return; // breaks referential types (objects) this[backingProperty] = val; // Schedule a render this._scheduleRender(); if (this.constructor.properties[key].attribute) { // TODO map prop name to attr name this.setAttribute(key, val); // Sync attribute } } }); if (_this.constructor.properties[key].attribute) { observedAttributes.push(key); // TODO map prop name to attr name } // Set default val based on type _this[backingProperty] = defaultValues[_this.constructor.properties[key].type]; }); return _this; } _createClass(RenderComponent, [{ key: 'connectedCallback', // Element appended to the DOM value: function connectedCallback() { var _this2 = this; this._scheduleRender(); Object.keys(this.constructor.properties).forEach(function (key) { // Set default property values (if defined) if ('value' in _this2.constructor.properties[key]) { _this2[key] = _this2.constructor.properties[key].value; } }); } }, { key: '_scheduleRender', value: function _scheduleRender() { var _this3 = this; if (this._renderScheduled) return; this._renderScheduled = true; requestAnimationFrame(function () { _this3._renderScheduled = false; _this3.render(); }); } }, { key: 'attributeChangedCallback', value: function attributeChangedCallback(attributeName, oldValue, newValue) { if (_get(RenderComponent.prototype.__proto__ || Object.getPrototypeOf(RenderComponent.prototype), 'attributeChangedCallback', this)) { _get(RenderComponent.prototype.__proto__ || Object.getPrototypeOf(RenderComponent.prototype), 'attributeChangedCallback', this).call(this); } if (oldValue === newValue) return; var propertyName = attributeToPropertyName(attributeName); if (propertyName in this) { this[propertyName] = newValue; } } }]); return RenderComponent; }(HTMLElement); // Memoized maps of attribute to property names and vice versa. var attributeToPropertyNames = {}; var propertyNamesToAttributes = {}; /** * Convert hyphenated foo-bar attribute name to camel case fooBar property name. */ function attributeToPropertyName(attributeName) { var propertyName = attributeToPropertyNames[attributeName]; if (!propertyName) { // Convert and memoize. var hyphenRegEx = /-([a-z])/g; propertyName = attributeName.replace(hyphenRegEx, function (match) { return match[1].toUpperCase(); }); attributeToPropertyNames[attributeName] = propertyName; } return propertyName; } exports.RenderComponent = RenderComponent;