domql 0.0.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/package.json +54 -21
  4. package/packages/cookie/index.js +22 -0
  5. package/packages/emotion/index.js +47 -0
  6. package/packages/object/index.js +29 -0
  7. package/packages/object/package.json +20 -0
  8. package/packages/routeLink/index.js +23 -0
  9. package/packages/router/index.js +18 -0
  10. package/src/element/assign.js +22 -0
  11. package/src/element/cache.js +52 -0
  12. package/src/element/create.js +144 -0
  13. package/src/element/createNode.js +92 -0
  14. package/src/element/createProps.js +64 -0
  15. package/src/element/createState.js +55 -0
  16. package/src/element/define.js +13 -0
  17. package/src/element/id.js +10 -0
  18. package/src/element/index.js +34 -0
  19. package/src/element/iterate.js +80 -0
  20. package/src/element/methods.js +96 -0
  21. package/src/element/mixins/attr.js +18 -0
  22. package/src/element/mixins/classList.js +37 -0
  23. package/src/element/mixins/content.js +17 -0
  24. package/src/element/mixins/data.js +21 -0
  25. package/src/element/mixins/html.js +17 -0
  26. package/src/element/mixins/index.js +23 -0
  27. package/src/element/mixins/registry.js +55 -0
  28. package/src/element/mixins/state.js +16 -0
  29. package/src/element/mixins/style.js +14 -0
  30. package/src/element/mixins/text.js +19 -0
  31. package/src/element/nodes.js +141 -0
  32. package/src/element/parse.js +17 -0
  33. package/src/element/proto.js +66 -0
  34. package/src/element/root.js +10 -0
  35. package/src/element/set.js +46 -0
  36. package/src/element/tree.js +5 -0
  37. package/src/element/update.js +83 -0
  38. package/src/event/can.js +10 -0
  39. package/src/event/index.js +11 -0
  40. package/src/event/is.js +13 -0
  41. package/src/event/on.js +33 -0
  42. package/src/event/store.js +6 -0
  43. package/src/event/wrappers.js +14 -0
  44. package/src/index.js +16 -0
  45. package/src/utils/index.js +6 -0
  46. package/src/utils/node.js +10 -0
  47. package/src/utils/object.js +193 -0
  48. package/src/utils/protoUtils.js +119 -0
  49. package/src/utils/report.js +62 -0
  50. package/index.js +0 -15
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 rackai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # DOMQL
2
+ DOM rendering Javascript framework.
3
+
4
+ - Minimalistic
5
+ - No dependencies
6
+ - Extendable
7
+ - No transpilations, simple ES6 code
8
+ - One-time import and subtrees
9
+
10
+ You can start with [starter-kit](https://github.com/rackai/starter-kit) as a boilerplate, or jump into the live editor [playground](https://domql.com/playground/).
11
+
12
+ [![npm version](https://badge.fury.io/js/%40rackai%2Fdomql.svg)](https://badge.fury.io/js/%40rackai%2Fdomql)
13
+ [![Build Status](https://travis-ci.org/rackai/domql.svg?branch=master)](https://travis-ci.org/rackai/domql)
14
+ [![Coverage Status](https://coveralls.io/repos/github/rackai/domql/badge.svg?branch=main)](https://coveralls.io/github/rackai/domql?branch=main)
15
+
16
+ TODO:
17
+ - [x] error reporting
18
+ - [x] virtual DOM tree
19
+ - [x] create
20
+ - [x] create using prototype class
21
+ - [x] support multiple level prototypes
22
+ - [x] DOM caching
23
+ - [x] state
24
+ - [x] binding
25
+ - [x] with other component
26
+ - [x] with state
27
+ - [x] update
28
+ - [x] set (recreate)
29
+ - [x] only iterate with diff
30
+ - [x] events
31
+ - [x] event handling
32
+ - [ ] bubbling and propogation
33
+ - [ ] run changes inside animationFrame
34
+
35
+ ### Getting started
36
+
37
+ To install all dependencies and run dev server, run:
38
+
39
+ ```shell
40
+ yarn && yarn start
41
+ ```
42
+
43
+ ### Examples
44
+
45
+ Initialization:
46
+
47
+ ```javascript
48
+ import DOM from '@rackai/domql'
49
+
50
+ DOM.create({ text: 'Rendered' })
51
+ ```
52
+
53
+ Attributes:
54
+
55
+ ```javascript
56
+ var link = {
57
+ tag: 'a',
58
+ class: 'menu link',
59
+ attr: {
60
+ href: '#'
61
+ }
62
+ }
63
+ ```
64
+ ```javascript
65
+ var img = {
66
+ tag: 'img',
67
+ class: 'avatar',
68
+ attr: {
69
+ src: '...'
70
+ }
71
+ }
72
+ ```
73
+
74
+ Reusing:
75
+ ```javascript
76
+ var Link = {
77
+ tag: 'a'
78
+ }
79
+
80
+ var ListItem = {
81
+ proto: Link,
82
+ class: 'ui link',
83
+ attr: {
84
+ href: '#'
85
+ }
86
+ }
87
+
88
+ var menu = {
89
+ childProto: ListItem,
90
+ home: 'Home',
91
+ text: 'About'
92
+ }
93
+
94
+ var header = {
95
+ logo: {},
96
+ menu
97
+ }
98
+ ```
99
+
100
+ Array Support:
101
+ ```javascript
102
+ var navItems = ['Home', 'About', 'FAQ', 'Contact']
103
+
104
+ var menu = {
105
+ proto: ListItem,
106
+ ...navItems
107
+ }
108
+ ```
109
+
110
+ Update:
111
+ ```javascript
112
+ var val = {
113
+ text: 0
114
+ }
115
+
116
+ var Increment = {
117
+ tag: 'button',
118
+ text: 'Increment',
119
+ on: {
120
+ click: (e) => {
121
+ val.update({ text: val.text++ })
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## API
128
+
129
+ ### Properties
130
+
131
+ | Property | Type | Description | Default |
132
+ | --- | --- | --- | --- |
133
+ | `key` | `Number` `String` | Defines the key of the Element | The key of the object, or randomly generated name |
134
+ | `proto` | `Object` `Array` | Clones the other element | `undefined` |
135
+ | `childProto` | `Object` `Array` | Specifies the `proto` for all child elements | `undefined` |
136
+ | `tag` | `String` | Specifis the HTML tag | `div` or related HTML tag if the key matches |
137
+ | `class` | `Any` | Specifies the HTML class | `undefined` |
138
+ | `attr` | `Object` | Specifies the set of HTML attributes | `{}` |
139
+ | `text` | `Any` | Text inside the element | `undefined` |
140
+ | `content` | `Object` `Array` | Fragment wrapper to use dynamic content loading | `undefined`
141
+
142
+ To specify your own property per Element, set the function inside `define` property like:
143
+
144
+ ```javascript
145
+ var User = {
146
+ define: {
147
+ username: param => param.toUpperCase()
148
+ },
149
+ text: element => element.username
150
+ }
151
+
152
+ var Contact = {
153
+ proto: User,
154
+ username: 'nikoloza'
155
+ }
156
+ ```
157
+
158
+ ### Methods
159
+ | Method | Description | Params |
160
+ | --- | --- | --- |
161
+ | `update` | Updates element by passed object | `properties`: `Object` `Array` |
162
+ | `set` | Sets passed element in the `content` property | `element`: `Object` `Array` |
163
+
164
+
165
+ ### Events
166
+ All native DOM events are supported and can be specified inside `on` parameter. Additionally, `init` and `render` can be also invoked. All events except these two receive `event` object as a first parameter, following the `element` object itself.
167
+
168
+
169
+
170
+ ### Reserved keywords
171
+
172
+ ```
173
+ key
174
+ tag
175
+ node
176
+ proto
177
+ on
178
+ class
179
+ text
180
+ data
181
+ style
182
+ attr
183
+ update
184
+ set
185
+ define
186
+ ```
187
+
188
+ Anything except these keywords will create a new nested child element. The easier method to specify HTML tag is to use related nodeName as a key, for example:
189
+
190
+ ```javascript
191
+ var layout = { // this will be <div>
192
+ header: {}, // will create <header>
193
+ aside: {}, // will create <aside>
194
+ main: { // will create <main>
195
+ childProto: {
196
+ article: { // will create <article>
197
+ title: {}, // will create <div>
198
+ description: {}, // will create <div>
199
+ _rating: {} // will create <div class="rating">
200
+ }
201
+ }
202
+ },
203
+ footer: {} // will create <footer>
204
+ }
205
+ ```
206
+
207
+ ### Credits
208
+ Inspired by [brisky](https://github.com/vigour-io/brisky)
package/package.json CHANGED
@@ -1,25 +1,58 @@
1
1
  {
2
2
  "name": "domql",
3
- "version": "0.0.1",
4
- "main": "dist/index.js",
5
- "license": "MIT",
6
- "source": "index.js",
3
+ "description": "DOM rendering Javascript framework at early stage.",
4
+ "private": false,
5
+ "author": "rackai",
6
+ "version": "1.3.1",
7
+ "repository": "https://github.com/rackai/domql",
8
+ "publishConfig": {
9
+ "registry": "https://registry.npmjs.org"
10
+ },
11
+ "main": "src/index.js",
12
+ "files": [
13
+ "src",
14
+ "packages"
15
+ ],
16
+ "scripts": {
17
+ "start": "parcel examples/index.html --no-cache",
18
+ "build": "parcel build examples/index.html",
19
+ "standard": "npx standard \"src/**/*.js\"",
20
+ "test": "yarn standard && jest --coverage --coverageReporters=text-lcov | coveralls",
21
+ "test-watch": "jest --watch",
22
+ "bump": "npx np"
23
+ },
24
+ "source": true,
7
25
  "dependencies": {
8
- "@domql/cache": "latest",
9
- "@domql/cookie": "latest",
10
- "@domql/define": "latest",
11
- "@domql/element": "latest",
12
- "@domql/event": "latest",
13
- "@domql/id": "latest",
14
- "@domql/mixins": "latest",
15
- "@domql/node": "latest",
16
- "@domql/parse": "latest",
17
- "@domql/props": "latest",
18
- "@domql/proto": "latest",
19
- "@domql/registry": "latest",
20
- "@domql/report": "latest",
21
- "@domql/state": "latest",
22
- "@domql/tree": "latest",
23
- "@domql/utils": "latest"
24
- }
26
+ "regenerator-runtime": "^0.13.5"
27
+ },
28
+ "devDependencies": {
29
+ "@babel/core": "^7.10.4",
30
+ "@babel/preset-env": "^7.10.4",
31
+ "babel-eslint": "^10.0.3",
32
+ "babel-jest": "^27.0.2",
33
+ "babel-preset-env": "^1.7.0",
34
+ "coveralls": "^3.0.5",
35
+ "eslint": "^8.10.0",
36
+ "eslint-plugin-jest": "^26.1.0",
37
+ "jest": "^27.0.6",
38
+ "nodemon": "^2.0.6",
39
+ "np": "^7.2.0",
40
+ "parcel-bundler": "^1.12.4",
41
+ "standard": "^16.0.1"
42
+ },
43
+ "jest": {
44
+ "collectCoverageFrom": [
45
+ "src/**/*.js"
46
+ ]
47
+ },
48
+ "standard": {
49
+ "parser": "babel-eslint",
50
+ "env": [
51
+ "jest"
52
+ ]
53
+ },
54
+ "browserslist": [
55
+ "> 1%",
56
+ "ie >= 9"
57
+ ]
25
58
  }
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ export const isMobile = (() => /Mobi/.test(navigator.userAgent))()
4
+
5
+ export const setCookie = (cname, cvalue, exdays = 365) => {
6
+ const d = new Date()
7
+ d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000))
8
+ const expires = `expires=${d.toUTCString()}`
9
+ document.cookie = `${cname}=${cvalue};${expires};path=/`
10
+ }
11
+
12
+ export const getCookie = (cname) => {
13
+ const name = `${cname}=`
14
+ const decodedCookie = decodeURIComponent(document.cookie)
15
+ const ca = decodedCookie.split(';')
16
+ for (let i = 0; i < ca.length; i++) {
17
+ let c = ca[i]
18
+ while (c.charAt(0) === ' ') c = c.substring(1)
19
+ if (c.indexOf(name) === 0) return c.substring(name.length, c.length)
20
+ }
21
+ return ''
22
+ }
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ import DOM from '../../src'
4
+ import { isObjectLike, exec } from '../../src/utils'
5
+ import { classList } from '../../src/element/mixins'
6
+ import createEmotion from '@emotion/css/create-instance'
7
+
8
+ const {
9
+ flush,
10
+ hydrate,
11
+ cx,
12
+ merge,
13
+ getRegisteredStyles,
14
+ injectGlobal,
15
+ keyframes,
16
+ css,
17
+ sheet,
18
+ cache
19
+ } = createEmotion({ key: 'symbols' })
20
+
21
+ const style = (params, element, node) => {
22
+ const execPareams = exec(params, element)
23
+ if (params) {
24
+ if (isObjectLike(element.class)) element.class.style = execPareams
25
+ else element.class = { style: execPareams }
26
+ }
27
+ classf(element.class, element, node)
28
+ }
29
+
30
+ const classf = (params, element, node) => {
31
+ if (isObjectLike(params)) {
32
+ const classObjHelper = {}
33
+ for (const key in params) {
34
+ const prop = exec(params[key], element)
35
+ const CSSed = css(prop)
36
+ classObjHelper[key] = CSSed
37
+ }
38
+ classList(classObjHelper, element, node)
39
+ }
40
+ }
41
+
42
+ DOM.define({
43
+ style,
44
+ class: classf
45
+ }, {
46
+ overwrite: true
47
+ })
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ export const isObject = arg => {
4
+ if (arg === null) return false
5
+ return (typeof arg === 'object') && (arg.constructor === Object)
6
+ }
7
+
8
+ export const isString = arg => typeof arg === 'string'
9
+
10
+ export const isNumber = arg => typeof arg === 'number'
11
+
12
+ export const isFunction = arg => typeof arg === 'function'
13
+
14
+ export const isArray = arg => Array.isArray(arg)
15
+
16
+ export const isObjectLike = arg => {
17
+ if (arg === null) return false
18
+ return (typeof arg === 'object')
19
+ }
20
+
21
+ export const isDefined = arg => {
22
+ return isObject(arg) ||
23
+ isObjectLike(arg) ||
24
+ isString(arg) ||
25
+ isNumber(arg) ||
26
+ isFunction(arg) ||
27
+ isArray(arg) ||
28
+ isObjectLike(arg)
29
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@domql/object",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "",
6
+ "main": "index.js",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/domql/domql.git"
13
+ },
14
+ "author": "Rackai",
15
+ "license": "ISC",
16
+ "bugs": {
17
+ "url": "https://github.com/domql/domql/issues"
18
+ },
19
+ "homepage": "https://github.com/domql/domql#readme"
20
+ }
@@ -0,0 +1,23 @@
1
+ 'use strict'
2
+
3
+ import { Link } from '@rackai/symbols'
4
+ import { deepMerge } from '../../src/utils'
5
+ import route from './router'
6
+
7
+ const RouteLink = {
8
+ on: {
9
+ click: (event, element, state) => {
10
+ const root = element.lookup('app')
11
+ const { href } = element.props
12
+ const firstThree = href[0] + href[1] + href[2]
13
+ if (href && firstThree !== 'htt' && firstThree !== 'ske') {
14
+ route(root, href, {})
15
+ event.preventDefault()
16
+ }
17
+ }
18
+ }
19
+ }
20
+
21
+ deepMerge(Link, RouteLink)
22
+
23
+ export default RouteLink
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ export const splitRoute = (route = window.location.pathname) => route.slice(1).split('/')
4
+
5
+ export default (rootElement, path, state = {}, level = 0, pushState = true) => {
6
+ const route = path || window.location.pathname
7
+ const routes = splitRoute(route)
8
+
9
+ const content = rootElement.routes[`/${routes[level]}`]
10
+
11
+ if (content) {
12
+ if (pushState) window.history.pushState(state, null, route)
13
+ rootElement.set({ proto: content })
14
+ .node.scrollIntoView({ behavior: 'smooth' })
15
+ }
16
+
17
+ if (level === 0) rootElement.state.update({ activePage: routes[level] })
18
+ }
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Receives child and parent nodes as parametes
5
+ * and assigns them into real DOM tree
6
+ */
7
+ export const appendNode = (node, parentNode) => {
8
+ parentNode.appendChild(node)
9
+ return node
10
+ }
11
+
12
+ /**
13
+ * Receives elements and assigns the first
14
+ * parameter as a child of the second one
15
+ */
16
+ export const assignNode = (element, parent, key) => {
17
+ parent[key || element.key] = element
18
+ if (element.tag !== 'shadow') {
19
+ appendNode(element.node, parent.node)
20
+ }
21
+ return element
22
+ }
@@ -0,0 +1,52 @@
1
+ 'use strict'
2
+
3
+ import { can } from '../event'
4
+ import { exec, isString, isTagRegistered, report } from '../utils'
5
+
6
+ const cachedElements = {}
7
+
8
+ const createNode = (element) => {
9
+ const { tag } = element
10
+ if (tag) {
11
+ if (tag === 'string') return document.createTextNode(element.text)
12
+ else if (tag === 'fragment') {
13
+ return document.createDocumentFragment()
14
+ } else if (tag === 'svg' || tag === 'path') { // change that
15
+ return document.createElementNS('http://www.w3.org/2000/svg', tag)
16
+ } else return document.createElement(tag)
17
+ } else {
18
+ return document.createElement('div')
19
+ }
20
+ }
21
+
22
+ const detectTag = element => {
23
+ let { tag, key } = element
24
+ tag = exec(tag, element)
25
+
26
+ if (tag === true) tag = key
27
+
28
+ if (isString(tag)) {
29
+ const tagExists = isTagRegistered(tag) > -1
30
+ if (tagExists) return tag
31
+ } else {
32
+ const isKeyATag = isTagRegistered(key) > -1
33
+ if (isKeyATag) return key
34
+ }
35
+
36
+ return 'div'
37
+ }
38
+
39
+ export default (element) => {
40
+ const tag = element.tag = detectTag(element)
41
+
42
+ if (!can.render(element)) {
43
+ return report('HTMLInvalidTag')
44
+ }
45
+
46
+ let cachedTag = cachedElements[tag]
47
+ if (!cachedTag) cachedTag = cachedElements[tag] = createNode(element)
48
+
49
+ const clonedNode = cachedTag.cloneNode(true)
50
+ if (tag === 'string') clonedNode.nodeValue = element.text
51
+ return clonedNode
52
+ }
@@ -0,0 +1,144 @@
1
+ 'use strict'
2
+
3
+ import root from './root'
4
+ import createNode from './createNode'
5
+ import { appendNode, assignNode } from './assign'
6
+ import { applyPrototype } from './proto'
7
+ import nodes from './nodes'
8
+ import set from './set'
9
+ import createState from './createState'
10
+ import createProps from './createProps'
11
+ import update from './update'
12
+ import * as on from '../event/on'
13
+ import { assignClass } from './mixins/classList'
14
+ import { isFunction, isNumber, isString, createID, isNode } from '../utils'
15
+ import { remove, lookup, log, keys, parse, parseDeep } from './methods'
16
+ import cacheNode from './cache'
17
+ // import { overwrite, clone, fillTheRest } from '../utils'
18
+
19
+ const ENV = process.env.NODE_ENV
20
+
21
+ /**
22
+ * Creating a domQL element using passed parameters
23
+ */
24
+ const create = (element, parent, key, options = {}) => {
25
+ // if ELEMENT is not given
26
+ if (element === undefined) element = {}
27
+ if (element === null) return
28
+
29
+ // define KEY
30
+ const assignedKey = element.key || key || createID.next().value
31
+
32
+ // if PARENT is not given
33
+ // if (parent === null) parent = root
34
+ // if (parent === undefined) parent = root
35
+ if (!parent) parent = root
36
+ if (isNode(parent)) parent = root[`${key}_parent`] = { node: parent }
37
+
38
+ // if (assignedKey === 'all') debugger
39
+
40
+ // if element is STRING
41
+ if (isString(element) || isNumber(element)) {
42
+ element = {
43
+ text: element,
44
+ tag: (!element.proto && parent.childProto && parent.childProto.tag) ||
45
+ ((nodes.body.indexOf(key) > -1) && key) || 'string'
46
+ }
47
+ }
48
+
49
+ // create PROTOtypal inheritance
50
+ applyPrototype(element, parent, options)
51
+
52
+ // enable STATE
53
+ element.state = createState(element, parent)
54
+
55
+ // console.groupCollapsed('Create:', assignedKey)
56
+ // console.log(element)
57
+
58
+ // create and assign a KEY
59
+ element.key = assignedKey
60
+
61
+ // set the PATH
62
+ if (ENV === 'test' || ENV === 'development') {
63
+ if (!parent.path) parent.path = []
64
+ element.path = parent.path.concat(assignedKey)
65
+ }
66
+
67
+ // if it already HAS A NODE
68
+ if (element.node) {
69
+ // console.log('hasNode!')
70
+ // console.groupEnd('Create:')
71
+ return assignNode(element, parent, assignedKey)
72
+ }
73
+
74
+ // run `on.init`
75
+ if (element.on && isFunction(element.on.init)) {
76
+ on.init(element.on.init, element, element.state)
77
+ }
78
+
79
+ // generate a CLASS name
80
+ assignClass(element)
81
+
82
+ // assign METHODS
83
+ element.set = set
84
+ element.update = update
85
+ element.remove = remove
86
+ element.lookup = lookup
87
+ if (ENV === 'test' || ENV === 'development') {
88
+ element.keys = keys
89
+ element.parse = parse
90
+ element.parseDeep = parseDeep
91
+ element.log = log
92
+ }
93
+
94
+ // enable TRANSFORM in data
95
+ if (!element.transform) element.transform = {}
96
+
97
+ // enable CACHING
98
+ if (!element.__cached) element.__cached = {}
99
+
100
+ // enable EXEC
101
+ if (!element.__exec) element.__exec = {}
102
+
103
+ // enable CHANGES storing
104
+ if (!element.__changes) element.__changes = []
105
+
106
+ // enable CHANGES storing
107
+ const hasRoot = parent.parent && parent.parent.key === ':root'
108
+ if (!element.__root) element.__root = hasRoot ? parent : parent.__root
109
+
110
+ // apply props settings
111
+ createProps(element, parent)
112
+
113
+ // console.log('cache.props:')
114
+ // console.log(cache.props)
115
+ // console.log('applied props:')
116
+ // console.log(element.props)
117
+ // console.log('element:')
118
+ // console.log(element)
119
+ // console.groupEnd('Create:')
120
+
121
+ // don't render IF in condition
122
+ if (isFunction(element.if) && !element.if(element, element.state)) {
123
+ // TODO: move as fragment
124
+ const ifFragment = cacheNode({ tag: 'fragment' })
125
+ element.__ifFragment = appendNode(ifFragment, parent.node)
126
+ element.__ifFalsy = true
127
+ return
128
+ }
129
+
130
+ // CREATE a real NODE
131
+ createNode(element)
132
+
133
+ // assign NODE
134
+ assignNode(element, parent, key)
135
+
136
+ // run `on.render`
137
+ if (element.on && isFunction(element.on.render)) {
138
+ on.render(element.on.render, element, element.state)
139
+ }
140
+
141
+ return element
142
+ }
143
+
144
+ export default create