domql 2.0.6 → 2.0.7

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/README.md +208 -0
  2. package/package.json +53 -20
  3. package/packages/cookie/index.js +22 -0
  4. package/packages/emotion/index.js +35 -0
  5. package/packages/object/index.js +29 -0
  6. package/packages/object/package.json +20 -0
  7. package/packages/routeLink/index.js +23 -0
  8. package/packages/router/index.js +18 -0
  9. package/src/element/assign.js +22 -0
  10. package/src/element/cache.js +52 -0
  11. package/src/element/create.js +144 -0
  12. package/src/element/createNode.js +92 -0
  13. package/src/element/createProps.js +64 -0
  14. package/src/element/createState.js +51 -0
  15. package/src/element/define.js +13 -0
  16. package/src/element/id.js +10 -0
  17. package/src/element/index.js +34 -0
  18. package/src/element/iterate.js +80 -0
  19. package/src/element/methods.js +96 -0
  20. package/src/element/mixins/attr.js +18 -0
  21. package/src/element/mixins/classList.js +37 -0
  22. package/src/element/mixins/content.js +17 -0
  23. package/src/element/mixins/data.js +21 -0
  24. package/src/element/mixins/html.js +17 -0
  25. package/src/element/mixins/index.js +23 -0
  26. package/src/element/mixins/registry.js +55 -0
  27. package/src/element/mixins/state.js +16 -0
  28. package/src/element/mixins/style.js +14 -0
  29. package/src/element/mixins/text.js +19 -0
  30. package/src/element/nodes.js +139 -0
  31. package/src/element/parse.js +17 -0
  32. package/src/element/proto.js +66 -0
  33. package/src/element/root.js +10 -0
  34. package/src/element/set.js +46 -0
  35. package/src/element/tree.js +5 -0
  36. package/src/element/update.js +100 -0
  37. package/src/event/can.js +10 -0
  38. package/src/event/index.js +11 -0
  39. package/src/event/is.js +13 -0
  40. package/src/event/on.js +33 -0
  41. package/src/event/store.js +6 -0
  42. package/src/event/wrappers.js +14 -0
  43. package/src/index.js +16 -0
  44. package/src/utils/index.js +6 -0
  45. package/src/utils/node.js +10 -0
  46. package/src/utils/object.js +193 -0
  47. package/src/utils/protoUtils.js +119 -0
  48. package/src/utils/report.js +62 -0
  49. package/allExports.js +0 -17
  50. package/index.js +0 -15
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": "2.0.6",
4
- "main": "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": "2.0.7",
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/define": "latest",
10
- "@domql/element": "latest",
11
- "@domql/event": "latest",
12
- "@domql/extends": "latest",
13
- "@domql/key": "latest",
14
- "@domql/mixins": "latest",
15
- "@domql/node": "latest",
16
- "@domql/parse": "latest",
17
- "@domql/props": "latest",
18
- "@domql/registry": "latest",
19
- "@domql/report": "latest",
20
- "@domql/state": "latest",
21
- "@domql/tree": "latest",
22
- "@domql/utils": "latest"
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": "^7.12.1",
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
+ ]
23
53
  },
24
- "gitHead": "88144a3105a3a0abd5f54f31659a37e494418dcb"
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,35 @@
1
+ 'use strict'
2
+
3
+ import DOM from '../../src'
4
+ import { isObjectLike, exec } from '../../src/utils'
5
+ import { classList } from '../../src/element/mixins'
6
+
7
+ import { css } from '@emotion/css'
8
+
9
+ const style = (params, element, node) => {
10
+ const execPareams = exec(params, element)
11
+ if (params) {
12
+ if (isObjectLike(element.class)) element.class.style = execPareams
13
+ else element.class = { style: execPareams }
14
+ }
15
+ classf(element.class, element, node)
16
+ }
17
+
18
+ const classf = (params, element, node) => {
19
+ if (isObjectLike(params)) {
20
+ const classObjHelper = {}
21
+ for (const key in params) {
22
+ const prop = exec(params[key], element)
23
+ const CSSed = css(prop)
24
+ classObjHelper[key] = CSSed
25
+ }
26
+ classList(classObjHelper, element, node)
27
+ }
28
+ }
29
+
30
+ DOM.define({
31
+ style,
32
+ class: classf
33
+ }, {
34
+ overwrite: true
35
+ })
@@ -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
+ // enable STATE
50
+ element.state = createState(element, parent)
51
+
52
+ // create PROTOtypal inheritance
53
+ applyPrototype(element, parent, options)
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
+ // generate a CLASS name
75
+ assignClass(element)
76
+
77
+ // assign METHODS
78
+ element.set = set
79
+ element.update = update
80
+ element.remove = remove
81
+ element.lookup = lookup
82
+ if (ENV === 'test' || ENV === 'development') {
83
+ element.keys = keys
84
+ element.parse = parse
85
+ element.parseDeep = parseDeep
86
+ element.log = log
87
+ }
88
+
89
+ // run `on.init`
90
+ if (element.on && isFunction(element.on.init)) {
91
+ on.init(element.on.init, element, element.state)
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