babel-plugin-gruu
Version:
Babel plugin for transpiling JSX to Gruu
775 lines (668 loc) • 24.9 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _gruujs = __webpack_require__(1);
var _gruujs2 = _interopRequireDefault(_gruujs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var store = _gruujs2.default.createComponent({
state: { date: new Date() }
});
var lamps = _gruujs2.default.createComponent({
state: {
selected: {
params: [{ label: 'PZ: ', value: '2342342' }, { label: 'PZ: ', value: '2342342' }, { label: 'PZ: ', value: '2342342' }],
actions: [{ label: 'DELETE', func: function func() {
return console.log('sdfds');
} }]
},
selectConnection: function selectConnection(_ref) {
var id = _ref.id,
pz = _ref.pz,
circuit = _ref.circuit;
// console.log(lamps.state.selected)
lamps.state.selected = {
params: [{ label: 'ID: ', value: id }, { label: 'PZ: ', value: pz }, { label: 'Circuit: ', value: circuit }],
actions: [{ label: 'DELETE', func: function func() {
return console.log('delete');
} }]
};
}
}
});
var footer = _gruujs2.default.createComponent({
_type: 'div',
children: [_gruujs2.default.createComponent({
$children: function $children() {
var _lamps$state$selected = lamps.state.selected,
params = _lamps$state$selected.params,
actions = _lamps$state$selected.actions;
return [].concat(_toConsumableArray(params.map(function (_ref2) {
var label = _ref2.label,
value = _ref2.value;
return _gruujs2.default.createComponent({
_type: 'div',
children: [_gruujs2.default.createComponent({
_type: 'span',
children: [label]
}), _gruujs2.default.createComponent({
_type: 'span',
children: [value]
})],
style: { marginRight: '20px' }
});
})), [_gruujs2.default.createComponent({
_type: 'div',
style: { flex: 1 }
})], _toConsumableArray(actions.map(function (_ref3) {
var label = _ref3.label,
func = _ref3.func;
return _gruujs2.default.createComponent({
_type: 'button',
children: [label],
onclick: func
});
})));
}
})],
style: {
position: 'fixed',
bottom: '0px',
width: '100vw',
height: '80px',
backgroundColor: 'rgba(255, 255, 255, 0.8)',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '20px',
boxSizing: 'border-box'
}
});
setInterval(function () {
// console.log(Math.random())
var id = Math.random();
console.log(id);
lamps.state.selectConnection({ id: id, circuit: Math.random(), pz: Math.random() });
}, 1000);
var container = document.querySelector('#root');
_gruujs2.default.renderApp(container, [footer]);
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
const Gruu = ((function () {
const exists = value => value || value === '' || value === 0
const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
const uuid = () => `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`
const proxyAwareArrayFunctions = ['push', 'unshift']
const alterKeyCondition = key => key === 'children' || key.startsWith('_') || key.startsWith('$')
const stateModificationHandler = ({ object, actions, value, modifyTree }) => {
if (modifyTree) {
if (actions.length === 0) {
object.state = value
} else {
const lastAction = actions.slice(-1)[0]
const v = actions.slice(0, -1).reduce((acc, key) => acc[key], object)
v[lastAction] = value
}
}
}
const get = (object, actions) => actions.reduce((acc, key) => acc[key], object)
const findClosestNodeParent = object => (object._node ? object : findClosestNodeParent(object._parent))
const clearListeners = (component, paramsTuRemove) => {
if (component._isRendered && component._watchers) {
Object.keys(component._watchers).forEach((w) => {
if (paramsTuRemove) {
const set = component._watchers[w]._listeners[component._id].keys
set.forEach((key) => {
const param = key.split('->')[1].trim()
if (paramsTuRemove.includes(param)) {
set.delete(key)
}
})
if (set.size === 0) {
delete component._watchers[w]._listeners[component._id]
delete component._watchers[w]
}
} else {
delete component._watchers[w]._listeners[component._id]
delete component._watchers[w]
}
})
}
}
const updateDynamicProperty = (component, key, value) => {
if (key.startsWith('$')) {
const pureKey = key.slice(1)
processStack.push({ component, key })
domModificator({
object: component,
actions: [pureKey],
value: value ? value() : component[key](),
modifyTree: true
})
processStack.pop()
}
}
const childrenModificationHandler = ({ object, actions, value, valueParent, modifyTree }) => {
const lastIndexChildren = actions.lastIndexOf('children')
const action = actions.slice(lastIndexChildren + 1)[0]
const target = get(object, actions)
if (action === undefined) {
const preTarget = get(object, actions.slice(0, -1))
if (!preTarget.children) {
preTarget.children = []
}
const valueArray = Array.isArray(value) ? value : [value]
const length = preTarget.children.length - valueArray.length
const val = valueArray.concat(Array(length < 0 ? 0 : length))
let i
for (i = 0; i < val.length;) {
const currentChild = preTarget.children[i]
const newChild = val[i]
if (!currentChild || !newChild || !currentChild._key || !newChild._key || currentChild._key === newChild._key) {
domModificator({ object, actions: [...actions, `${i}`], value: newChild, valueParent, modifyTree })
i += 1
} else {
currentChild._unmount()
preTarget.children = [
...preTarget.children.slice(0, i),
...preTarget.children.slice(i + 1)
]
}
}
} else if (!isNaN(parseInt(action, 10))) {
if (target !== (value && (value.noProxy || value))) {
const preTarget = get(object, actions.slice(0, -2))
if (exists(target) && !exists(value)) {
target._unmount()
if (modifyTree) {
preTarget.children[action] = value
target._parent.children[action] = value
}
} else if (exists(target) && exists(value)) {
clearListeners(target)
if ((target._type || value._type) && (!target._type || !value._type || target._type !== value._type)) {
let component = value.noProxy || value
component = recursivelyCreateAndRenderComponent({ component, parent: preTarget })
target._unmount()
const nodeParent = findClosestNodeParent(preTarget)
const parentNodeArray = componentToNodeArray(nodeParent, true)
const targetNodeArray = componentToNodeArray(target)
const componentNodeArray = componentToNodeArray(component)
const lastTargetNode = targetNodeArray.slice(-1)[0]
let index = parentNodeArray.findIndex(({ id }) => id === lastTargetNode.id)
if (index !== -1) {
index += 1
for (let i = index; i < parentNodeArray.length; i += 1) {
if (parentNodeArray[i] && parentNodeArray[i].node &&
parentNodeArray[i].node.parentNode === nodeParent._node) {
index = i
break
}
}
}
componentNodeArray.forEach(({ node }) => {
if (node) {
nodeParent._node.insertBefore(node, parentNodeArray[index] && parentNodeArray[index].node)
}
})
if (modifyTree) {
preTarget.children[action] = component
target._parent.children[action] = component
}
} else {
const component = value.noProxy || value
Object.keys(target).concat(Object.keys(component)).forEach((key) => {
component[key] = component[key] || (alterKeyCondition(key) ? target[key] : component[key])
})
const componentKeys = Object.keys(component)
componentKeys.forEach((key) => {
if (!key.startsWith('_') && !key.startsWith('$')) {
domModificator({ object, actions: [...actions, key], value: component[key], valueParent: component })
}
})
componentKeys.forEach((key) => {
if (key.startsWith('$')) {
updateDynamicProperty(component, key)
}
})
if (modifyTree) {
target._parent.children[action] = component
preTarget.children[action] = component
} else if (valueParent) {
valueParent.children[action] = component
}
}
} else if (!exists(target) && exists(value)) {
let component = value.noProxy || value
const parent = findClosestNodeParent(preTarget)
component = recursivelyCreateAndRenderComponent({ component, parent: preTarget })
const parentNodeArray = componentToNodeArray(parent, true)
let index = parentNodeArray.findIndex(({ id }) => id === object._id)
const componentNodeArray = componentToNodeArray(component)
if (index !== -1) {
index += 1
for (let i = index; i < parentNodeArray.length; i += 1) {
if (parentNodeArray[i] && parentNodeArray[i].node &&
parentNodeArray[i].node.parentNode === parent._node) {
index = i
break
}
}
}
componentNodeArray.forEach(({ node }) => {
if (node) {
parent._node.insertBefore(node, parentNodeArray[index] && parentNodeArray[index].node)
}
})
if (modifyTree) {
preTarget.children[action] = component
} else if (valueParent) {
valueParent.children[action] = component
}
}
}
}
}
const nodeModificationHandler = ({ object, actions, value, modifyTree }) => {
const lastIndexChildren = actions.lastIndexOf('style')
const action = actions.slice(lastIndexChildren + 1)[0]
if (lastIndexChildren !== -1) {
if (action === undefined) {
const target = get(object, actions.slice(0, lastIndexChildren))
if (!value) {
target._node.removeAttribute('style')
if (modifyTree) {
target.style = value
}
} else {
const newStyle = Object.assign({}, target.style, value)
if (!target.style) {
target.style = {}
}
Object.keys(newStyle).forEach((key) => {
if (target.style[key] !== value[key]) {
target._node.style[key] = value[key] || ''
if (modifyTree) {
target.style[key] = value[key]
}
}
})
}
} else {
const target = get(object, actions.slice(0, -2))
target._node.style[action] = value
if (modifyTree) {
if (!target.style) {
target.style = {}
}
target.style[action] = value
}
}
} else {
const target = get(object, actions.slice(0, -1))
const lastAction = actions.slice(-1)[0]
if (target[lastAction] !== value) {
if (modifyTree) {
target[lastAction] = value
}
if (target._node) {
target._node[lastAction] = value
}
}
}
}
const destinations = {
INTERNAL: 'INTERNAL',
DEFAULT: 'DEFAULT',
STATE: 'STATE',
CHILDREN: 'CHILDREN',
NODE: 'NODE',
NONE: 'NONE'
}
const findDestination = (actions = []) => {
let destination = ''
let isNode = true
for (const action of actions) {
if (destination === destinations.INTERNAL || action.startsWith('_')) {
return destinations.INTERNAL
} else if (destination === destinations.DEFAULT || action.startsWith('$')) {
return destinations.DEFAULT
} else if (destination === destinations.STATE || (action === 'state' && isNode)) {
return destinations.STATE
} else if (action === 'children' && isNode) {
destination = destinations.CHILDREN
isNode = false
} else if (destination === destinations.CHILDREN && !isNaN(parseInt(action, 10))) {
destination = destinations.CHILDREN
isNode = true
} else if (isNode) {
destination = destinations.NODE
isNode = true
}
}
return destination
}
const defaultModificationHandler = ({ object, actions, value, modifyTree }) => {
const target = get(object, actions.slice(0, -1))
const action = actions.slice(-1)[0]
if (modifyTree) {
target[action] = value
}
}
const domModificator = ({ object: obj, actions, value, valueParent, modifyTree }) => {
const destination = findDestination(actions)
const object = obj.noProxy || obj
switch (destination) {
case destinations.STATE:
stateModificationHandler({ object, actions, value, modifyTree })
break
case destinations.CHILDREN:
childrenModificationHandler({ object, actions, value, valueParent, modifyTree })
break
case destinations.NODE:
nodeModificationHandler({ object, actions, value, modifyTree })
break
case destinations.DEFAULT:
defaultModificationHandler({ object, actions, value, modifyTree })
break
default:
break
}
}
const handler = (object, ...k) => ({
get (target, key) {
if (key === 'noProxy') {
return target
}
if (typeof key === 'string' && key.startsWith('_')) {
return target[key]
}
const { component: stackElement, key: stackKey } = processStack.slice(-1)[0] || {}
if (stackElement) {
if (!object._listeners) {
object._listeners = {}
}
const newKey = [...k, key].join('.')
if (!object._listeners[stackElement._id]) {
object._listeners[stackElement._id] = {
keys: new Set()
}
}
object._listeners[stackElement._id].component = stackElement
object._listeners[stackElement._id].keys.add(`${newKey} -> ${stackKey}`)
if (!stackElement._watchers) {
stackElement._watchers = {}
}
stackElement._watchers[object._id] = object
}
const isType = target[key] && (target[key]._type || target[key].children)
const component = isType ? target[key] : object
if (target[key] && typeof target[key] === 'object') {
return new Proxy(target[key].noProxy || target[key], handler(component, ...(isType ? [] : [...k, key])))
}
if (typeof target[key] === 'function' && !proxyAwareArrayFunctions.includes(key)) {
return target[key].bind(target)
}
return target[key]
},
set (target, key, value) {
const actions = [...k, key]
domModificator({ object, actions, value, modifyTree: true })
if (object._rerender) {
clearTimeout(object._rerender)
}
object._rerender = setTimeout(() => {
const _actions = actions.length > 1 ? actions.slice(0, -1).join('.') : actions[0]
if (object._listeners) {
const listenersIds = Object.keys(object._listeners)
listenersIds.forEach((id) => {
if (object._listeners[id]) {
const { component, keys } = object._listeners[id]
const paramsTuUpdate = Object.keys(component).reduce((acc, param) => [
...acc.filter(p => p !== param),
...(param.startsWith('$') && keys.has(`${_actions} -> ${param.split('.')[0]}`) ? [param] : [])
], [])
clearListeners(component, paramsTuUpdate)
paramsTuUpdate.forEach((param) => {
updateDynamicProperty(component, param)
})
}
})
}
})
return true
}
})
const createElement = (component) => {
const node = document.createElement(component._type)
Object.keys(component).forEach((key) => {
if (key.startsWith('_') || key.startsWith('$')) {
return
}
switch (key) {
case 'style':
Object.keys(component[key]).forEach((cssProp) => {
node.style[cssProp] = component[key][cssProp]
})
break
case 'children':
case 'state':
return
default:
node[key] = component[key]
}
})
return node
}
const processStack = []
const internallyCreateComponent = (object) => {
const component = object.noProxy || object
component._id = component._id || uuid()
Object.keys(component).forEach((key) => {
component[key] = typeof component[key] === 'function'
? component[key].bind(new Proxy(component, handler(component)))
: component[key]
})
Object.keys(component).forEach((key) => {
if (key.startsWith('$')) {
const pureKey = key.slice(1)
processStack.push({ component, key })
const value = component[key]()
component[pureKey] = Array.isArray(value) || key !== '$children' ? value : [value]
processStack.pop()
}
})
if (component.children && Array.isArray(component.children)) {
component.children = component.children.map(child => (child && child.noProxy) || child)
}
component._unmount = function () {
clearListeners(this)
if (this._isRendered) {
if (this._node) {
const nodeParent = findClosestNodeParent(this._parent)
nodeParent._node.removeChild(this._node)
} else if (this.children) {
this.children.forEach((child) => {
if (child) {
child._unmount()
}
})
}
}
}
return component
}
const recursivelyCreateAndRenderComponent = ({ component: obj, parent, nodeParent }) => {
const object = (!exists(obj) || typeof obj === 'object') ? obj : { _type: 'text', textContent: obj }
if (!object || object._isRendered) {
if (object && object._isRendered) {
Object.keys(object).forEach((key) => {
updateDynamicProperty(object, key)
})
}
return object
}
const component = internallyCreateComponent(object)
internallyRenderComponent({ component, parent, nodeParent })
if (component.children) {
if (!Array.isArray(component.children)) {
component.children = [component.children]
}
component.children = component.children.map(child => (
recursivelyCreateAndRenderComponent({
component: child,
parent: component,
nodeParent: component._node ? component : nodeParent
})
))
}
component._isRendered = true
return component
}
const createComponent = (obj) => {
const object = (!exists(obj) || typeof obj === 'object') ? obj : { _type: 'text', textContent: obj }
if (!object) {
return object
}
object._id = object._id || uuid()
return new Proxy(object, handler(object))
}
const internallyRenderComponent = ({ component, parent, nodeParent }) => {
const pureComponent = component && (component.noProxy || component)
if (pureComponent) {
if (pureComponent._type) {
pureComponent._node = pureComponent._type === 'text'
? document.createTextNode(pureComponent.textContent)
: createElement(pureComponent)
}
pureComponent._parent = parent.noProxy || parent
if (nodeParent && pureComponent._node) {
nodeParent._node.appendChild(pureComponent._node)
}
}
}
const attachComponent = (component) => {
const pureComponent = component && (component.noProxy || component)
if (pureComponent) {
if (pureComponent._node) {
const nodeParent = findClosestNodeParent(pureComponent._parent)
nodeParent._node.appendChild(pureComponent._node)
return
}
if (pureComponent.children) {
pureComponent.children.forEach(attachComponent)
}
}
}
const componentToNodeArray = (component, next) => {
const pureComponent = component && (component.noProxy || component)
if (pureComponent) {
if (pureComponent._node && !next) {
return [{ id: pureComponent._id, node: pureComponent._node }]
}
if (pureComponent.children) {
return pureComponent.children.reduce((acc, child) =>
acc.concat(child ? componentToNodeArray(child) : [{ id: pureComponent._id }]), []
)
}
}
return []
}
const renderApp = (root, children) => {
const component = createComponent({ children }).noProxy
const parent = { _node: root, children: [component] }
recursivelyCreateAndRenderComponent({ component, parent, nodeParent: parent })
attachComponent(component)
}
const browserHistory = createComponent({
state: {
locationPath: window.location.pathname,
goTo (path) {
browserHistory.state.locationPath = path
window.history.pushState(null, null, path)
}
}
})
const isPathCorrect = (path, locationPath) => path === locationPath
const route = (path, component) => createComponent({
$children () {
return [isPathCorrect(path, browserHistory.state.locationPath) && component]
}
})
return Object.assign(
{ createComponent, renderApp, browserHistory, route },
window.__DEV__ ? { destinations, findDestination } : {}
)
})())
if (true) {
module.exports = Gruu
}
/***/ })
/******/ ]);