@lightningjs/blits 2.0.0-beta.2 → 2.0.0-beta.4
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.
- package/CHANGELOG.md +19 -0
- package/index.d.ts +40 -11
- package/package.json +4 -3
- package/scripts/prepublishOnly.js +2 -2
- package/src/application.js +95 -3
- package/src/component/base/methods.js +1 -2
- package/src/component/setup/state.js +2 -0
- package/src/component.js +57 -23
- package/src/components/Circle.js +4 -3
- package/src/components/FPScounter.js +1591 -1578
- package/src/components/RouterView.js +2 -1
- package/src/components/Sprite.js +16 -1
- package/src/components/index.js +0 -2
- package/src/engines/L3/element.js +9 -0
- package/src/engines/L3/launch.js +4 -1
- package/src/{focus.js → focus/focus.js} +6 -18
- package/src/focus/helpers.js +31 -0
- package/src/focus/hover.js +94 -0
- package/src/launch.js +1 -0
- package/src/lib/codegenerator/generator.js +4 -0
- package/src/lib/lifecycle.js +5 -0
- package/src/lib/log.js +4 -4
- package/src/lib/reactivityguard/computedprops.js +1 -1
- package/src/router/router.js +44 -13
- package/vscode/data/template-attributes.json +335 -86
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import Component from '../component.js'
|
|
19
19
|
import Router, { state as routerState } from '../router/router.js'
|
|
20
20
|
import symbols from '../lib/symbols.js'
|
|
21
|
-
import Focus from '../focus.js'
|
|
21
|
+
import Focus from '../focus/focus.js'
|
|
22
22
|
|
|
23
23
|
let hashchangeHandler = null
|
|
24
24
|
|
|
@@ -72,6 +72,7 @@ export default () =>
|
|
|
72
72
|
'content',
|
|
73
73
|
'placement',
|
|
74
74
|
'inspector-data',
|
|
75
|
+
'holder',
|
|
75
76
|
]
|
|
76
77
|
const elementConfigs = []
|
|
77
78
|
const forloops = []
|
package/src/components/Sprite.js
CHANGED
|
@@ -65,6 +65,7 @@ export default () =>
|
|
|
65
65
|
'content',
|
|
66
66
|
'placement',
|
|
67
67
|
'inspector-data',
|
|
68
|
+
'holder',
|
|
68
69
|
]
|
|
69
70
|
const elementConfigs = []
|
|
70
71
|
const forloops = []
|
|
@@ -91,7 +92,9 @@ export default () =>
|
|
|
91
92
|
elementConfigs[0]['h'] = parent.node.h * (100 / 100)
|
|
92
93
|
elementConfigs[0]['texture'] = component.texture
|
|
93
94
|
elementConfigs[0]['color'] = component.color
|
|
94
|
-
elementConfigs[0]['
|
|
95
|
+
elementConfigs[0]['rounded'] = component.rounded
|
|
96
|
+
elementConfigs[0]['border'] = component.border
|
|
97
|
+
elementConfigs[0]['shadow'] = component.shadow
|
|
95
98
|
elms[0].populate(elementConfigs[0])
|
|
96
99
|
|
|
97
100
|
if (inSlot === true) {
|
|
@@ -124,6 +127,15 @@ export default () =>
|
|
|
124
127
|
function anonymous(component, elms, context, components, rootComponent, skips, effect) {
|
|
125
128
|
elms[0].set('color', component.color)
|
|
126
129
|
},
|
|
130
|
+
function anonymous(component, elms, context, components, rootComponent, skips, effect) {
|
|
131
|
+
elms[0].set('rounded', component.rounded)
|
|
132
|
+
},
|
|
133
|
+
function anonymous(component, elms, context, components, rootComponent, skips, effect) {
|
|
134
|
+
elms[0].set('border', component.border)
|
|
135
|
+
},
|
|
136
|
+
function anonymous(component, elms, context, components, rootComponent, skips, effect) {
|
|
137
|
+
elms[0].set('shadow', component.shadow)
|
|
138
|
+
},
|
|
127
139
|
],
|
|
128
140
|
context: {},
|
|
129
141
|
},
|
|
@@ -132,6 +144,9 @@ export default () =>
|
|
|
132
144
|
map: undefined,
|
|
133
145
|
frame: undefined,
|
|
134
146
|
color: undefined,
|
|
147
|
+
rounded: undefined,
|
|
148
|
+
border: undefined,
|
|
149
|
+
shadow: undefined,
|
|
135
150
|
},
|
|
136
151
|
state() {
|
|
137
152
|
return {
|
package/src/components/index.js
CHANGED
|
@@ -18,11 +18,9 @@
|
|
|
18
18
|
import Circle from './Circle.js'
|
|
19
19
|
import RouterView from './RouterView.js'
|
|
20
20
|
import Sprite from './Sprite.js'
|
|
21
|
-
import FPScounter from './FPScounter.js'
|
|
22
21
|
|
|
23
22
|
export default () => ({
|
|
24
23
|
Circle: Circle(),
|
|
25
24
|
RouterView: RouterView(),
|
|
26
25
|
Sprite: Sprite(),
|
|
27
|
-
FPScounter: FPScounter(),
|
|
28
26
|
})
|
|
@@ -24,6 +24,8 @@ import symbols from '../../lib/symbols.js'
|
|
|
24
24
|
import Settings from '../../settings.js'
|
|
25
25
|
import shaders from '../../lib/shaders/shaders.js'
|
|
26
26
|
|
|
27
|
+
const holderComponentMap = new WeakMap()
|
|
28
|
+
|
|
27
29
|
/**
|
|
28
30
|
* Creates a padding object from a value and direction.
|
|
29
31
|
* @param {number|object|string|undefined} padding - The padding value.
|
|
@@ -523,6 +525,9 @@ const propsTransformer = {
|
|
|
523
525
|
this.props['data'] = v
|
|
524
526
|
}
|
|
525
527
|
},
|
|
528
|
+
set holder(v) {
|
|
529
|
+
this.props['interactive'] = v
|
|
530
|
+
},
|
|
526
531
|
}
|
|
527
532
|
|
|
528
533
|
export const elementAttributes = Object.keys(propsTransformer)
|
|
@@ -578,6 +583,10 @@ const Element = {
|
|
|
578
583
|
? renderer.createTextNode({ ...textDefaults, ...this.props.props })
|
|
579
584
|
: renderer.createNode(this.props.props)
|
|
580
585
|
|
|
586
|
+
if (this.props['holder'] === true) {
|
|
587
|
+
holderComponentMap.set(this.node, this.component)
|
|
588
|
+
}
|
|
589
|
+
|
|
581
590
|
if (props['@loaded'] !== undefined && typeof props['@loaded'] === 'function') {
|
|
582
591
|
this.node.on('loaded', (el, { type, dimensions }) => {
|
|
583
592
|
props['@loaded']({ w: dimensions.w, h: dimensions.h, type }, this)
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -100,6 +100,7 @@ export default (App, target, settings = {}) => {
|
|
|
100
100
|
textureMemory: textureMemorySettings(settings),
|
|
101
101
|
createImageBitmapSupport: 'auto',
|
|
102
102
|
targetFPS: 'maxFPS' in settings ? settings.maxFPS : 0,
|
|
103
|
+
platform: 'platform' in settings ? settings.platform : null,
|
|
103
104
|
},
|
|
104
105
|
...(settings.advanced || {}),
|
|
105
106
|
},
|
|
@@ -118,7 +119,9 @@ export default (App, target, settings = {}) => {
|
|
|
118
119
|
|
|
119
120
|
shaderLoader()
|
|
120
121
|
fontLoader()
|
|
121
|
-
|
|
122
|
+
// Defer app initialization until after the current call stack is cleared,
|
|
123
|
+
// allowing the renderer to finish setting up before the app starts creating components
|
|
124
|
+
Promise.resolve().then(initApp)
|
|
122
125
|
|
|
123
126
|
return renderer
|
|
124
127
|
}
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
* SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import symbols from '
|
|
19
|
-
import { state } from '
|
|
20
|
-
import Settings from '
|
|
21
|
-
import { DEFAULT_HOLD_TIMEOUT_MS } from '
|
|
22
|
-
import { Log } from '
|
|
18
|
+
import symbols from '../lib/symbols.js'
|
|
19
|
+
import { state } from '../router/router.js'
|
|
20
|
+
import Settings from '../settings.js'
|
|
21
|
+
import { DEFAULT_HOLD_TIMEOUT_MS } from '../constants.js'
|
|
22
|
+
import { Log } from '../lib/log.js'
|
|
23
|
+
import { getAncestors } from './helpers.js'
|
|
23
24
|
|
|
24
25
|
let focusedComponent = null
|
|
25
26
|
let focusChain = []
|
|
@@ -99,19 +100,6 @@ export default {
|
|
|
99
100
|
},
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
/**
|
|
103
|
-
* Recursive function that retrieves the ancestors of a component
|
|
104
|
-
* @param {Array} components
|
|
105
|
-
* @returns array components
|
|
106
|
-
*/
|
|
107
|
-
const getAncestors = (components) => {
|
|
108
|
-
if (components[0][symbols.parent] !== undefined) {
|
|
109
|
-
components.unshift(components[0][symbols.parent])
|
|
110
|
-
return getAncestors(components)
|
|
111
|
-
}
|
|
112
|
-
return components
|
|
113
|
-
}
|
|
114
|
-
|
|
115
103
|
/**
|
|
116
104
|
* Get the component in the ancestors chain that has a handler for a certain key code
|
|
117
105
|
* @param {Object} component
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 symbols from '../lib/symbols.js'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Recursive function that retrieves the ancestors of a component
|
|
22
|
+
* @param {Array} components
|
|
23
|
+
* @returns array components
|
|
24
|
+
*/
|
|
25
|
+
export const getAncestors = (components) => {
|
|
26
|
+
if (components[0][symbols.parent] !== undefined) {
|
|
27
|
+
components.unshift(components[0][symbols.parent])
|
|
28
|
+
return getAncestors(components)
|
|
29
|
+
}
|
|
30
|
+
return components
|
|
31
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 { Log } from '../lib/log.js'
|
|
19
|
+
import { getAncestors } from './helpers.js'
|
|
20
|
+
import symbols from '../lib/symbols.js'
|
|
21
|
+
|
|
22
|
+
let hoveredComponent = null
|
|
23
|
+
let hoverChain = []
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
get() {
|
|
27
|
+
return hoveredComponent
|
|
28
|
+
},
|
|
29
|
+
set(component) {
|
|
30
|
+
if (component === undefined || component.eol === true) return
|
|
31
|
+
|
|
32
|
+
// early return if already hovered
|
|
33
|
+
if (component === hoveredComponent) return
|
|
34
|
+
|
|
35
|
+
if (hoveredComponent === null) {
|
|
36
|
+
hoverChain = getAncestors([component])
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// unhover currently hovered components
|
|
40
|
+
if (hoveredComponent !== null) {
|
|
41
|
+
if (hoverChain[hoverChain.length - 1] === component.$parent) {
|
|
42
|
+
hoverChain.push(component)
|
|
43
|
+
} else {
|
|
44
|
+
const newhoverChain = getAncestors([component])
|
|
45
|
+
let i = hoverChain.length
|
|
46
|
+
while (i--) {
|
|
47
|
+
// don't unhover when part of the new hover chain
|
|
48
|
+
if (newhoverChain.indexOf(hoverChain[i]) > -1) break
|
|
49
|
+
// skip if component is destroyed
|
|
50
|
+
if (hoverChain[i].eol !== true) {
|
|
51
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
hoverChain = newhoverChain
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ensure that all components in the hover path have hover state
|
|
59
|
+
let i = 0
|
|
60
|
+
while (i < hoverChain.length - 1) {
|
|
61
|
+
// skip if component is destroyed
|
|
62
|
+
if (hoverChain[i].eol !== true) {
|
|
63
|
+
hoverChain[i][symbols.lifecycle].state = 'hover'
|
|
64
|
+
}
|
|
65
|
+
i++
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setHover(component)
|
|
69
|
+
},
|
|
70
|
+
clear() {
|
|
71
|
+
if (hoveredComponent === null) return
|
|
72
|
+
for (let i = 0; i < hoverChain.length; i++) {
|
|
73
|
+
if (hoverChain[i].eol !== true) {
|
|
74
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
hoveredComponent = null
|
|
78
|
+
hoverChain = []
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Set the hover to the Component
|
|
84
|
+
* @param {Object} component - The component to hover
|
|
85
|
+
*/
|
|
86
|
+
const setHover = (component) => {
|
|
87
|
+
Log.info(
|
|
88
|
+
'\nHover chain:\n',
|
|
89
|
+
hoverChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c.$componentId).join('\n')
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
hoveredComponent = component
|
|
93
|
+
component[symbols.lifecycle].state = 'hover'
|
|
94
|
+
}
|
package/src/launch.js
CHANGED
|
@@ -88,6 +88,7 @@ async function rendererVersion() {
|
|
|
88
88
|
* @property {number} [textureProcessingTimeLimit] - Max time renderer can process textures in a frame
|
|
89
89
|
* @property {Partial<import('@lightningjs/renderer').RendererMainSettings>} [advanced] - Advanced renderer settings
|
|
90
90
|
* @property {boolean} [announcer] - Whether or not the announcer should be activated on initialization
|
|
91
|
+
* @property {boolean} [enableMouse] - Enable mouse support (hover and click-to-focus). Defaults to false.
|
|
91
92
|
* @property {number} [maxFPS] - Maximum FPS
|
|
92
93
|
*/
|
|
93
94
|
|
|
@@ -186,6 +186,10 @@ const generateElementCode = function (
|
|
|
186
186
|
renderCode.push(`elementConfigs[${counter}][Symbol.for('isSlot')] = true`)
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
if (options.holder) {
|
|
190
|
+
renderCode.push(`elementConfigs[${counter}]['holder'] = true`)
|
|
191
|
+
}
|
|
192
|
+
|
|
189
193
|
Object.keys(templateObject).forEach((key) => {
|
|
190
194
|
if (key === 'slot') {
|
|
191
195
|
renderCode.push(`
|
package/src/lib/lifecycle.js
CHANGED
|
@@ -31,6 +31,8 @@ const states = [
|
|
|
31
31
|
'ready', // fired when component instantiated, reactivity setup done and template spawned
|
|
32
32
|
'focus', // fired when receiving focus (can occur multiple times)
|
|
33
33
|
'unfocus', // fired when losing focus (can occur multiple times)
|
|
34
|
+
'hover', // fired when receiving focus (can occur multiple times)
|
|
35
|
+
'unhover', // fired when losing focus (can occur multiple times)
|
|
34
36
|
'destroy', // fired when component is destroyed and removed
|
|
35
37
|
'attach', // fired when entering the viewport margin and attached to the render tree
|
|
36
38
|
'detach', // fired when leaving the viewport margin and detached from the render tree
|
|
@@ -90,6 +92,9 @@ export default {
|
|
|
90
92
|
inspectorEnabled = Settings.get('inspector', false)
|
|
91
93
|
}
|
|
92
94
|
}
|
|
95
|
+
// update the built-in isHovered state variable
|
|
96
|
+
if (v === 'hover') this.component[symbols.state].isHovered = true
|
|
97
|
+
if (v === 'unhover') this.component[symbols.state].isHovered = false
|
|
93
98
|
if (v === 'focus') {
|
|
94
99
|
this.component[symbols.state].$hasFocus = true
|
|
95
100
|
if (
|
package/src/lib/log.js
CHANGED
|
@@ -46,7 +46,7 @@ const logger = (context) => {
|
|
|
46
46
|
return (
|
|
47
47
|
((level >= 1 || (Array.isArray(level) && level.indexOf('info') > -1)) &&
|
|
48
48
|
console.info.bind(
|
|
49
|
-
|
|
49
|
+
console,
|
|
50
50
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
51
51
|
'background-color: #0284c7; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
52
52
|
'color: ##94a3b8;'
|
|
@@ -61,7 +61,7 @@ const logger = (context) => {
|
|
|
61
61
|
return (
|
|
62
62
|
((level >= 1 || (Array.isArray(level) && level.indexOf('warn') > -1)) &&
|
|
63
63
|
console.warn.bind(
|
|
64
|
-
|
|
64
|
+
console,
|
|
65
65
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
66
66
|
'background-color: #fbbf24; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
67
67
|
'color: ##94a3b8;'
|
|
@@ -76,7 +76,7 @@ const logger = (context) => {
|
|
|
76
76
|
return (
|
|
77
77
|
((level >= 1 || (Array.isArray(level) && level.indexOf('error') > -1)) &&
|
|
78
78
|
console.error.bind(
|
|
79
|
-
|
|
79
|
+
console,
|
|
80
80
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
81
81
|
'background-color: #dc2626; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
82
82
|
'color: ##94a3b8;'
|
|
@@ -91,7 +91,7 @@ const logger = (context) => {
|
|
|
91
91
|
return (
|
|
92
92
|
((level >= 2 || (Array.isArray(level) && level.indexOf('debug') > -1)) &&
|
|
93
93
|
console.debug.bind(
|
|
94
|
-
|
|
94
|
+
console,
|
|
95
95
|
`%c ⚡️ ${context} %c (${new Date().toLocaleTimeString([], {
|
|
96
96
|
hour: '2-digit',
|
|
97
97
|
minute: '2-digit',
|
|
@@ -195,7 +195,7 @@ export default (code) => {
|
|
|
195
195
|
if (thisRefs.size > 0) {
|
|
196
196
|
// Skip if already modified
|
|
197
197
|
if (
|
|
198
|
-
prop.body.includes(commentText) ||
|
|
198
|
+
prop.body.includes(commentText.trim()) ||
|
|
199
199
|
Array.from(thisRefs).some((ref) => prop.body.startsWith(ref))
|
|
200
200
|
) {
|
|
201
201
|
continue
|
package/src/router/router.js
CHANGED
|
@@ -21,7 +21,7 @@ import { reactive } from '../lib/reactivity/reactive.js'
|
|
|
21
21
|
import symbols from '../lib/symbols.js'
|
|
22
22
|
import { Log } from '../lib/log.js'
|
|
23
23
|
import { stage } from '../launch.js'
|
|
24
|
-
import Focus from '../focus.js'
|
|
24
|
+
import Focus from '../focus/focus.js'
|
|
25
25
|
import Announcer from '../announcer/announcer.js'
|
|
26
26
|
import Settings from '../settings.js'
|
|
27
27
|
|
|
@@ -216,12 +216,17 @@ const defaultOptions = {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
const makeRouteObject = (route, overrides) => {
|
|
219
|
+
// FIX: exclude keepAlive from the destination route options. Unlike other
|
|
220
|
+
// overrides, keepAlive applies to the route being LEFT, not the destination.
|
|
221
|
+
// It is consumed by removeView() instead.
|
|
222
|
+
const { keepAlive: _keepAlive, ...destOverrides } = overrideOptions // eslint-disable-line no-unused-vars
|
|
223
|
+
|
|
219
224
|
const cleanRoute = {
|
|
220
225
|
hash: overrides.hash,
|
|
221
226
|
path: route.path,
|
|
222
227
|
component: route.component,
|
|
223
228
|
transition: 'transition' in route ? route.transition : fadeInFadeOutTransition,
|
|
224
|
-
options: { ...defaultOptions, ...route.options, ...
|
|
229
|
+
options: { ...defaultOptions, ...route.options, ...destOverrides },
|
|
225
230
|
announce: route.announce || false,
|
|
226
231
|
hooks: route.hooks || {},
|
|
227
232
|
data: { ...route.data, ...navigationData, ...overrides.queryParams },
|
|
@@ -251,7 +256,7 @@ export const navigate = async function () {
|
|
|
251
256
|
let reuse = false
|
|
252
257
|
if (preventHashChangeNavigation === false && this[symbols.parent][symbols.routes]) {
|
|
253
258
|
let previousRoute = currentRoute //? Object.assign({}, currentRoute) : undefined
|
|
254
|
-
let route = matchHash(getHash(
|
|
259
|
+
let route = matchHash(getHash(location.hash), this[symbols.parent][symbols.routes])
|
|
255
260
|
|
|
256
261
|
currentRoute = route
|
|
257
262
|
|
|
@@ -262,7 +267,11 @@ export const navigate = async function () {
|
|
|
262
267
|
const hooks = this[symbols.parent][symbols.routerHooks]
|
|
263
268
|
if (hooks.beforeEach) {
|
|
264
269
|
try {
|
|
265
|
-
beforeEachResult = await hooks.beforeEach.call(
|
|
270
|
+
beforeEachResult = await hooks.beforeEach.call(
|
|
271
|
+
this[symbols.parent],
|
|
272
|
+
route,
|
|
273
|
+
previousRoute
|
|
274
|
+
)
|
|
266
275
|
if (isString(beforeEachResult)) {
|
|
267
276
|
currentRoute = previousRoute
|
|
268
277
|
to(beforeEachResult)
|
|
@@ -303,7 +312,11 @@ export const navigate = async function () {
|
|
|
303
312
|
let beforeHookOutput
|
|
304
313
|
if (route.hooks.before) {
|
|
305
314
|
try {
|
|
306
|
-
beforeHookOutput = await route.hooks.before.call(
|
|
315
|
+
beforeHookOutput = await route.hooks.before.call(
|
|
316
|
+
this[symbols.parent],
|
|
317
|
+
route,
|
|
318
|
+
previousRoute
|
|
319
|
+
)
|
|
307
320
|
if (isString(beforeHookOutput)) {
|
|
308
321
|
currentRoute = previousRoute
|
|
309
322
|
to(beforeHookOutput)
|
|
@@ -342,8 +355,12 @@ export const navigate = async function () {
|
|
|
342
355
|
|
|
343
356
|
// add the previous route (technically still the current route at this point)
|
|
344
357
|
// into the history stack when inHistory is true and we're not navigating back
|
|
358
|
+
//
|
|
359
|
+
// FIX: use truthy check instead of `!== undefined` because matchHash()
|
|
360
|
+
// can return `false`, which survives `!== undefined` but has no `.options`.
|
|
345
361
|
if (
|
|
346
|
-
previousRoute
|
|
362
|
+
previousRoute &&
|
|
363
|
+
previousRoute.options &&
|
|
347
364
|
previousRoute.options.inHistory === true &&
|
|
348
365
|
navigatingBack === false
|
|
349
366
|
) {
|
|
@@ -485,7 +502,8 @@ export const navigate = async function () {
|
|
|
485
502
|
|
|
486
503
|
// apply out out transition on previous view if available, unless
|
|
487
504
|
// we're reusing the prvious page component
|
|
488
|
-
|
|
505
|
+
// FIX: truthy guard — previousRoute can be `false` (see history-push comment above).
|
|
506
|
+
if (previousRoute && reuse === false) {
|
|
489
507
|
// only animate when there is a previous route
|
|
490
508
|
shouldAnimate = true
|
|
491
509
|
const oldView = this[symbols.children].splice(1, 1).pop()
|
|
@@ -512,7 +530,7 @@ export const navigate = async function () {
|
|
|
512
530
|
if (hooks.afterEach) {
|
|
513
531
|
try {
|
|
514
532
|
await hooks.afterEach.call(
|
|
515
|
-
this.parent,
|
|
533
|
+
this[symbols.parent],
|
|
516
534
|
route, // to
|
|
517
535
|
previousRoute // from
|
|
518
536
|
)
|
|
@@ -525,7 +543,7 @@ export const navigate = async function () {
|
|
|
525
543
|
if (route.hooks.after) {
|
|
526
544
|
try {
|
|
527
545
|
await route.hooks.after.call(
|
|
528
|
-
this.parent,
|
|
546
|
+
this[symbols.parent],
|
|
529
547
|
route, // to
|
|
530
548
|
previousRoute // from
|
|
531
549
|
)
|
|
@@ -542,6 +560,12 @@ export const navigate = async function () {
|
|
|
542
560
|
}
|
|
543
561
|
}
|
|
544
562
|
|
|
563
|
+
// Clear module-level variables after removeView has consumed them.
|
|
564
|
+
// Placed here so it executes for all navigation flows, not only when
|
|
565
|
+
// previousRoute exists and reuse is false.
|
|
566
|
+
overrideOptions = {}
|
|
567
|
+
navigationData = {}
|
|
568
|
+
|
|
545
569
|
// reset navigating indicators
|
|
546
570
|
navigatingBack = false
|
|
547
571
|
state.navigating = false
|
|
@@ -569,11 +593,18 @@ const removeView = async (route, view, transition, navigatingBack) => {
|
|
|
569
593
|
}
|
|
570
594
|
}
|
|
571
595
|
|
|
596
|
+
// Resolve effective keepAlive: runtime override from $router.to() takes precedence
|
|
597
|
+
// over the static route config option
|
|
598
|
+
const keepAlive =
|
|
599
|
+
overrideOptions.keepAlive !== undefined
|
|
600
|
+
? overrideOptions.keepAlive
|
|
601
|
+
: route.options && route.options.keepAlive
|
|
602
|
+
|
|
572
603
|
// cache the page when it's as 'keepAlive' instead of destroying
|
|
573
604
|
if (
|
|
574
605
|
navigatingBack === false &&
|
|
575
606
|
route.options &&
|
|
576
|
-
|
|
607
|
+
keepAlive === true &&
|
|
577
608
|
route.options.inHistory === true
|
|
578
609
|
) {
|
|
579
610
|
const historyItem = history[history.length - 1]
|
|
@@ -588,7 +619,7 @@ const removeView = async (route, view, transition, navigatingBack) => {
|
|
|
588
619
|
* 2. Navigating back, and the previous route is configured with "keep alive" set to true.
|
|
589
620
|
* 3. Navigating back, and the previous route is not configured with "keep alive" set to true.
|
|
590
621
|
*/
|
|
591
|
-
if (route.options && (
|
|
622
|
+
if (route.options && (keepAlive !== true || navigatingBack === true)) {
|
|
592
623
|
view.destroy()
|
|
593
624
|
view = null
|
|
594
625
|
}
|
|
@@ -618,11 +649,11 @@ const setOrAnimate = (node, transition, shouldAnimate = true) => {
|
|
|
618
649
|
})
|
|
619
650
|
}
|
|
620
651
|
|
|
621
|
-
export const to = (
|
|
652
|
+
export const to = (path, data = {}, options = {}) => {
|
|
622
653
|
navigationData = data
|
|
623
654
|
overrideOptions = options
|
|
624
655
|
|
|
625
|
-
|
|
656
|
+
location.hash = path.replace(/^#/, '')
|
|
626
657
|
}
|
|
627
658
|
|
|
628
659
|
export const back = function () {
|