@lightningjs/blits 0.3.14 → 0.4.0

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.
@@ -17,25 +17,27 @@
17
17
 
18
18
  import { Log } from '../log.js'
19
19
 
20
+ import symbols from '../symbols.js'
21
+
20
22
  export default (component, state) => {
21
- component.___stateKeys = []
23
+ component[symbols.stateKeys] = []
22
24
 
23
25
  state = state.apply(component.prototype)
24
26
  Object.keys(state).forEach((key) => {
25
- if (component.___propKeys && component.___propKeys.indexOf(key) > -1) {
27
+ if (component[symbols.propKeys] && component[symbols.propKeys].indexOf(key) > -1) {
26
28
  Log.error(`State ${key} already exists as a prop`)
27
29
  }
28
- if (component.___methodKeys && component.___methodKeys.indexOf(key) > -1) {
30
+ if (component[symbols.methodKeys] && component[symbols.methodKeys].indexOf(key) > -1) {
29
31
  Log.error(`State ${key} already exists as a method`)
30
32
  }
31
- component.___stateKeys.push(key)
33
+ component[symbols.stateKeys].push(key)
32
34
  try {
33
35
  Object.defineProperty(component.prototype, key, {
34
36
  get() {
35
- return this.___state && key in this.___state && this.___state[key]
37
+ return this[symbols.state] && key in this[symbols.state] && this[symbols.state][key]
36
38
  },
37
39
  set(v) {
38
- if (this.___state) this.___state[key] = v
40
+ if (this[symbols.state]) this[symbols.state][key] = v
39
41
  },
40
42
  })
41
43
  } catch (e) {
@@ -15,18 +15,20 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
+ import symbols from '../symbols.js'
19
+
18
20
  export default (component, watchers) => {
19
- component.prototype.___watchKeys = []
20
- component.prototype.___watchers = {}
21
+ component.prototype[symbols.watchKeys] = []
22
+ component.prototype[symbols.watchers] = {}
21
23
 
22
24
  for (let watch in watchers) {
23
25
  if (typeof watchers[watch] !== 'function') {
24
26
  console.warn(`${watch} is not a function`)
25
27
  }
26
28
 
27
- component.prototype.___watchKeys.push(watch)
29
+ component.prototype[symbols.watchKeys].push(watch)
28
30
 
29
- component.prototype.___watchers[watch] = function (v, old) {
31
+ component.prototype[symbols.watchers][watch] = function (v, old) {
30
32
  watchers[watch].call(this, v, old)
31
33
  }
32
34
  }
@@ -0,0 +1,41 @@
1
+ export default {
2
+ currentView: Symbol('currentView'),
3
+ computedKeys: Symbol('computedKeys'),
4
+ destroy: Symbol('destroy'),
5
+ index: Symbol('index'),
6
+ init: Symbol('init'),
7
+ inputEvents: Symbol('inputEvents'),
8
+ intervals: Symbol('intervals'),
9
+ _intervals: Symbol('_intervals'),
10
+ level: Symbol('level'),
11
+ methodKeys: Symbol('methodKeys'),
12
+ originalState: Symbol('originalState'),
13
+ propKeys: Symbol('propKeys'),
14
+ ready: Symbol('ready'),
15
+ renderer: Symbol('renderer'),
16
+ routes: Symbol('routes'),
17
+ settings: Symbol('settings'),
18
+ state: Symbol('state'),
19
+ stateKeys: Symbol('stateKeys'),
20
+ textnode: Symbol('textnode'),
21
+ timeouts: Symbol('timeouts'),
22
+ _timeouts: Symbol('_timeouts'),
23
+ type: Symbol('type'),
24
+ watchers: Symbol('watchers'),
25
+ watchKeys: Symbol('watchKeys'),
26
+
27
+ /* Utilizing the global Symbol registry for the following purposes */
28
+
29
+ // Symbol 'children' utilized within generated code
30
+ children: Symbol.for('children'),
31
+ // Symbol 'components' utilized within generated code
32
+ components: Symbol.for('components'),
33
+ // Symbol 'id' utilized within generated code
34
+ id: Symbol.for('id'),
35
+ // Symbol 'isSlot' utilized within generated code
36
+ isSlot: Symbol.for('isSlot'),
37
+ // Symbol 'props' utilized within generated code
38
+ props: Symbol.for('props'),
39
+ // Symbol 'slots' utilized within generated code
40
+ slots: Symbol.for('slots'),
41
+ }
@@ -15,9 +15,11 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
+ import symbols from '../symbols.js'
19
+
18
20
  class TemplateParseError extends Error {
19
- constructor(name, context) {
20
- super('TemplateParseError')
21
+ constructor(message, name, context) {
22
+ super(`TemplateParseError ${message}`)
21
23
  this.name = name
22
24
  this.context = context
23
25
  }
@@ -44,7 +46,13 @@ export default (template = '') => {
44
46
  try {
45
47
  return format(tags)
46
48
  } catch (error) {
47
- console.error('Error:', error.message)
49
+ if (error instanceof TemplateParseError) {
50
+ console.error(`${error.message} | ${error.name}`)
51
+ } else {
52
+ console.error(error)
53
+ }
54
+ // return errors gracefully
55
+ return null
48
56
  }
49
57
  }
50
58
 
@@ -76,7 +84,7 @@ export default (template = '') => {
76
84
  const parseEmptyTagStart = () => {
77
85
  const match = moveCursorOnMatch(emptyTagStartRegex)
78
86
  if (match) {
79
- tags.push({ type: null, __type: 'opening', __level: currentLevel })
87
+ tags.push({ type: null, [symbols.type]: 'opening', [symbols.level]: currentLevel })
80
88
  currentLevel++
81
89
  parseLoop(parseEmptyTagStart)
82
90
  } else {
@@ -88,7 +96,7 @@ export default (template = '') => {
88
96
  const match = moveCursorOnMatch(emptyTagEndRegex)
89
97
  if (match) {
90
98
  currentLevel--
91
- tags.push({ type: null, __type: 'closing', __level: currentLevel })
99
+ tags.push({ type: null, [symbols.type]: 'closing', [symbols.level]: currentLevel })
92
100
  parseLoop(parseEmptyTagStart)
93
101
  } else {
94
102
  parseLoop(parseTag)
@@ -100,9 +108,9 @@ export default (template = '') => {
100
108
  if (match) {
101
109
  if (match[0].startsWith('</')) {
102
110
  currentLevel--
103
- currentTag = { type: match[1], __type: 'closing', __level: currentLevel }
111
+ currentTag = { type: match[1], [symbols.type]: 'closing', [symbols.level]: currentLevel }
104
112
  } else {
105
- currentTag = { type: match[1], __type: 'opening', __level: currentLevel }
113
+ currentTag = { type: match[1], [symbols.type]: 'opening', [symbols.level]: currentLevel }
106
114
  currentLevel++
107
115
  }
108
116
  parseLoop(parseTagEnd)
@@ -115,13 +123,13 @@ export default (template = '') => {
115
123
  const match = moveCursorOnMatch(tagEndRegex)
116
124
  if (match) {
117
125
  if (match[1] === '/>') {
118
- currentTag.__type = 'self-closing'
126
+ currentTag[symbols.type] = 'self-closing'
119
127
  currentLevel-- // because it was parsed as opening tag before
120
128
  }
121
129
 
122
130
  // parsing content in between tags
123
131
  // rule: < char cannot be used in between tags even in escaped form
124
- if (currentTag.__type === 'opening') {
132
+ if (currentTag[symbols.type] === 'opening') {
125
133
  const tagContent = template.slice(cursor, template.indexOf('<', cursor))
126
134
  if (tagContent) {
127
135
  currentTag.content = tagContent
@@ -172,12 +180,12 @@ export default (template = '') => {
172
180
  let output = { children: [] }
173
181
 
174
182
  for (const item of data) {
175
- const { type, __type, __level } = item
183
+ const { type, [symbols.type]: __type, [symbols.level]: __level } = item
176
184
 
177
185
  // Check for unclosed tags
178
- while (stack.length && stack[stack.length - 1].__level >= __level) {
186
+ while (stack.length && stack[stack.length - 1][symbols.level] >= __level) {
179
187
  const popped = stack.pop()
180
- if (popped.__type === 'opening') {
188
+ if (popped[symbols.type] === 'opening') {
181
189
  throw new TemplateParseError('MismatchedClosingTag', `tag: ${popped.type || 'null'}`)
182
190
  }
183
191
  }
@@ -200,8 +208,8 @@ export default (template = '') => {
200
208
 
201
209
  // Create a new item, copying properties but deleting __type and __level
202
210
  const newItem = { ...item }
203
- delete newItem.__type
204
- delete newItem.__level
211
+ delete newItem[symbols.type]
212
+ delete newItem[symbols.level]
205
213
 
206
214
  if (__type === 'opening') {
207
215
  newItem.children = []
@@ -0,0 +1,166 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ import { default as fadeInFadeOutTransition } from './transitions/fadeInOut.js'
19
+
20
+ import symbols from '../lib/symbols.js'
21
+ import { Log } from '../lib/log.js'
22
+ import Element from '../element.js'
23
+ import Focus from '../focus.js'
24
+
25
+ export let currentRoute
26
+ export let navigating = false
27
+
28
+ const cacheMap = new WeakMap()
29
+
30
+ export const getHash = () => {
31
+ return (document.location.hash || '/').replace(/^#/, '')
32
+ }
33
+
34
+ export const matchHash = (path, routes = []) => {
35
+ const route = routes
36
+ .filter((r) => {
37
+ return r.path === path
38
+ })
39
+ .pop()
40
+ if (route) currentRoute = route
41
+ return route
42
+ }
43
+
44
+ export const navigate = async function () {
45
+ navigating = true
46
+ if (this.parent[symbols.routes]) {
47
+ const previousRoute = currentRoute
48
+ const hash = getHash()
49
+ const route = matchHash(hash, this.parent[symbols.routes])
50
+
51
+ if (route) {
52
+ // apply default transition if none specified
53
+ if (!('transition' in route)) {
54
+ route.transition = fadeInFadeOutTransition
55
+ }
56
+ // a transition can be a function returning a dynamic transition object
57
+ // based on current and previous route
58
+ if (typeof route.transition === 'function') {
59
+ route.transition = route.transition(previousRoute, route)
60
+ }
61
+
62
+ let holder
63
+ let { view, focus } = cacheMap.get(route) || {}
64
+
65
+ if (!view) {
66
+ // create a holder element for the new view
67
+ holder = Element({ parent: this[symbols.children][0] })
68
+ holder.populate({})
69
+ holder.set('w', '100%')
70
+ holder.set('h', '100%')
71
+ view = route.component(this[symbols.props], holder, this)
72
+ } else {
73
+ holder = view.wrapper
74
+ }
75
+
76
+ this[symbols.children].push(view)
77
+
78
+ // apply before settings to holder element
79
+ if (route.transition.before) {
80
+ if (Array.isArray(route.transition.before)) {
81
+ for (let i = 0; i < route.transition.before.length; i++) {
82
+ holder.set(route.transition.before[i].prop, route.transition.before[i].value)
83
+ }
84
+ } else {
85
+ holder.set(route.transition.before.prop, route.transition.before.value)
86
+ }
87
+ }
88
+
89
+ let shouldAnimate = false
90
+
91
+ // apply out out transition on previous view
92
+ if (previousRoute) {
93
+ // only animate when there is a previous route
94
+ shouldAnimate = true
95
+ const oldView = this[symbols.children].splice(1, 1).pop()
96
+ if (oldView) {
97
+ removeView(previousRoute, oldView, route.transition.out)
98
+ }
99
+ }
100
+
101
+ // apply in transition
102
+ if (route.transition.in) {
103
+ if (Array.isArray(route.transition.in)) {
104
+ for (let i = 0; i < route.transition.in.length; i++) {
105
+ i === route.transition.length - 1
106
+ ? await setOrAnimate(holder, route.transition.in[i], shouldAnimate)
107
+ : setOrAnimate(holder, route.transition.in[i], shouldAnimate)
108
+ }
109
+ } else {
110
+ await setOrAnimate(holder, route.transition.in, shouldAnimate)
111
+ }
112
+ }
113
+
114
+ // focus the new view
115
+ focus ? Focus.set(focus) : view.focus()
116
+ } else {
117
+ Log.error(`Route ${hash} not found`)
118
+ }
119
+ }
120
+ navigating = false
121
+ }
122
+
123
+ const removeView = async (route, view, transition) => {
124
+ // apply out transition
125
+ if (transition) {
126
+ if (Array.isArray(transition)) {
127
+ for (let i = 0; i < transition.length; i++) {
128
+ i === transition.length - 1
129
+ ? await setOrAnimate(view.wrapper, transition[i])
130
+ : setOrAnimate(view.wrapper, transition[i])
131
+ }
132
+ } else {
133
+ await setOrAnimate(view.wrapper, transition)
134
+ }
135
+ }
136
+
137
+ // cache the page when it's as 'keepAlive' instead of destroying
138
+ if (route.options && route.options.keepAlive === true) {
139
+ cacheMap.set(route, { view: view, focus: Focus.get() })
140
+ } else {
141
+ // remove and cleanup
142
+ for (let i = 0; i < view[symbols.children].length - 1; i++) {
143
+ if (view[symbols.children][i] && view[symbols.children][i].destroy) {
144
+ view[symbols.children][i].destroy()
145
+ view[symbols.children][i] = null
146
+ }
147
+ }
148
+ view.destroy()
149
+ view = null
150
+ }
151
+ }
152
+
153
+ const setOrAnimate = (node, transition, shouldAnimate = true) => {
154
+ return shouldAnimate
155
+ ? node.animate(transition.prop, transition)
156
+ : node.set(transition.prop, transition.value)
157
+ }
158
+
159
+ export const to = (location) => {
160
+ window.location.hash = `#${location}`
161
+ }
162
+
163
+ export default {
164
+ navigate,
165
+ to,
166
+ }
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ export default {
19
+ before: {
20
+ prop: 'alpha',
21
+ value: 0,
22
+ },
23
+ in: {
24
+ prop: 'alpha',
25
+ value: 1,
26
+ },
27
+ }
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ export default {
19
+ before: {
20
+ prop: 'alpha',
21
+ value: 0,
22
+ },
23
+ in: {
24
+ prop: 'alpha',
25
+ value: 1,
26
+ duration: 200,
27
+ },
28
+ out: {
29
+ prop: 'alpha',
30
+ value: 0,
31
+ duration: 100,
32
+ },
33
+ }
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ export { default as fadeIn } from './fadeIn.js'
19
+ export { default as fadeInOut } from './fadeInOut.js'
20
+ export { default as slideIn } from './slideIn.js'
21
+ export { default as slideInOut } from './slideInOut.js'
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ export default {
19
+ before: {
20
+ prop: 'x',
21
+ value: '-100%',
22
+ },
23
+ in: {
24
+ prop: 'x',
25
+ value: 0,
26
+ duration: 200,
27
+ },
28
+ }
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright 2023 Comcast Cable Communications Management, LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * SPDX-License-Identifier: Apache-2.0
16
+ */
17
+
18
+ export default {
19
+ before: {
20
+ prop: 'x',
21
+ value: '-100%',
22
+ },
23
+ in: {
24
+ prop: 'x',
25
+ value: 0,
26
+ duration: 200,
27
+ },
28
+ out: {
29
+ prop: 'x',
30
+ value: '100%',
31
+ duration: 200,
32
+ },
33
+ }
package/src/router.js CHANGED
@@ -17,6 +17,8 @@
17
17
 
18
18
  import { Log } from './lib/log.js'
19
19
 
20
+ import symbols from './lib/symbols.js'
21
+
20
22
  export const getHash = () => {
21
23
  return (document.location.hash || '/').replace(/^#/, '')
22
24
  }
@@ -31,26 +33,29 @@ export const matchHash = (path, routes = []) => {
31
33
  }
32
34
 
33
35
  export const navigate = function () {
34
- if (this.parent.___routes) {
36
+ if (this.parent[symbols.routes]) {
35
37
  const hash = getHash()
36
- const route = matchHash(hash, this.parent.___routes)
38
+ const route = matchHash(hash, this.parent[symbols.routes])
37
39
  if (route) {
38
- if (this.__currentView) {
39
- for (let i = 0; i < this.__currentView.___children.length - 1; i++) {
40
- if (this.__currentView.___children[i] && this.__currentView.___children[i].destroy) {
41
- this.__currentView.___children[i].destroy()
42
- this.__currentView.___children[i] = null
40
+ if (this[symbols.currentView]) {
41
+ for (let i = 0; i < this[symbols.currentView][symbols.children].length - 1; i++) {
42
+ if (
43
+ this[symbols.currentView][symbols.children][i] &&
44
+ this[symbols.currentView][symbols.children][i].destroy
45
+ ) {
46
+ this[symbols.currentView][symbols.children][i].destroy()
47
+ this[symbols.currentView][symbols.children][i] = null
43
48
  }
44
49
  }
45
- this.__currentView.destroy()
46
- this.__currentView = null
50
+ this[symbols.currentView].destroy()
51
+ this[symbols.currentView] = null
47
52
  }
48
- this.___children[1] = this.__currentView = route.component(
49
- this.___props,
50
- this.___children[0],
53
+ this[symbols.children][1] = this[symbols.currentView] = route.component(
54
+ this[symbols.props],
55
+ this[symbols.children][0],
51
56
  this
52
57
  )
53
- this.__currentView.focus()
58
+ this[symbols.currentView].focus()
54
59
  } else {
55
60
  Log.error(`Route ${hash} not found`)
56
61
  }
package/src/settings.js CHANGED
@@ -15,10 +15,16 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
+ import symbols from './lib/symbols.js'
19
+
18
20
  const settings = {
19
- ___settings: {},
21
+ [symbols.settings]: {},
20
22
  get(key, defaultValue = null) {
21
- return (key in this.___settings && this.___settings[key]) || defaultValue
23
+ if (key in this[symbols.settings]) {
24
+ return this[symbols.settings][key]
25
+ } else {
26
+ return defaultValue
27
+ }
22
28
  },
23
29
  set(key, value) {
24
30
  if (typeof key === 'object') {
@@ -26,7 +32,7 @@ const settings = {
26
32
  this.set(k, key[k])
27
33
  })
28
34
  } else {
29
- this.___settings[key] = value
35
+ this[symbols.settings][key] = value
30
36
  }
31
37
  },
32
38
  }
File without changes