Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5675687
feat: add passFocus option to router to prevent focusing RouterView o…
WoodingMP Jul 30, 2025
dfc18b9
Merge pull request #433 from WoodingMP/feat/skip-router-focus
michielvandergeest Aug 4, 2025
7def7b3
Added missing type definitions for RouteOptions.
michielvandergeest Aug 4, 2025
264a17b
Merge pull request #440 from lightning-js/feature/route-options-defin…
michielvandergeest Aug 4, 2025
6da6539
Merge branch 'master' into dev
michielvandergeest Aug 4, 2025
20506b5
Marked route options as optional in the type definitions.
michielvandergeest Aug 5, 2025
2783b93
Fixed timing issue where routerview would sometimes try to focus the …
michielvandergeest Aug 5, 2025
5e22526
Bumped version to 1.35.5 and updated changelog.
michielvandergeest Aug 6, 2025
89cf834
docs(plugins): add storage plugin documentation and remove duplicate …
il-sairamg Aug 8, 2025
970e7cc
Merge pull request #442 from il-sairamg/blits-storage-doc-update
michielvandergeest Aug 8, 2025
54c1bdf
Added debug logs to announcer. Fixed (?) issues with isProcessing. Op…
michielvandergeest Aug 8, 2025
3c1fd0b
Added remove as an alias (and the prefered name) for canceling a mess…
michielvandergeest Aug 11, 2025
c6bdd7c
Fixed typo in docs.
michielvandergeest Aug 11, 2025
1397e11
Removed duplication.
michielvandergeest Aug 11, 2025
479a850
Fixed example in documentation.
michielvandergeest Aug 11, 2025
b42d0ca
Merge pull request #443 from lightning-js/feature/announcer-debug-logs
michielvandergeest Aug 11, 2025
4a79f5a
Bumped version to 1.36.0 and updated changelog.
michielvandergeest Aug 11, 2025
76968ad
Fixed typo in changelog.
michielvandergeest Aug 11, 2025
11166be
Merge branch 'master' into dev
michielvandergeest Aug 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v1.36.0

_11 Aug 2025_

- Added `passFocus` option to route options to prevent focus being passed to page navigated to
- Added missing type definitions for Route options
- Fixed sidebar in docs
- Added debug log messages to Announcer
- Added `remove()` function as (preferred) alias for announcer `message.cancel()`
- Fixed issue with removing a messages causing an interrupt of current message being read out

## v1.35.5

_06 Aug 2025_
Expand Down
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
- [Language](/plugins/language.md)
- [Theme](/plugins/theme.md)
- [Global App State](/plugins/global_app_state.md)
- [Storage](/plugins/storage.md)
- Performance
- [Lazy loading]('/performance/lazy-loading.md')
8 changes: 4 additions & 4 deletions docs/plugins/text-to-speech-announcer.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ In some cases you may not want to clear the entire queue, but instead cancel out

Imagine an App with a row of tiles, it's possible that before the title of the role is being spoken out, the user already navigates through the tiles within the row. Traditionally you'd use the focus event to speak out info about each tile (i.e. adding tot the queue). You don't want all previously focused tiles to still be announced, but would still want the category of the row to be announced, making clearing the queue not required.

The `speak()`-method return a Promise that also contains a `cancel()` function. When called, it will cancel that specific message and remove it from the queue before it can be spoken out.
The `speak()`-method return a Promise that also contains a `remove()` function. When called, it will remove it from the queue before it can be spoken out.

Additionally if you want to _interrupt_ a specific messages as it's being spoken out as well and go straight to the next message in the queue (i.e. the newly focused item, for example). You can use the `stop()` message that is returned on the Promise returned by the `speak()`-method.

Expand All @@ -100,8 +100,8 @@ Blits.Component('MyTile', {
unfocus() {
// when unfocused interrupt the message if it's already being spoken out
this.message.stop()
// and cancel the message to remove it from the queue
this.message.cancel()
// and remove the message from the queue
this.message.remove()
}
}
})
Expand All @@ -117,4 +117,4 @@ Alternatively the announcer can be enabled or disabled run time by using one of

- `this.$announcer.enable()` - activates the announcer
- `this.$announcer.disable()` - deactivates the announcer
- `this.$announcer.disable(true/false)` - turns the announcer or on off
- `this.$announcer.disable(true/false)` - turns the announcer on or off
2 changes: 2 additions & 0 deletions docs/router/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export default Blits.Component('Poster', {

Whenever you navigate to a new page, the URL hash will automatically be updated. Unless specified otherwise, navigating to a new page, will add that route to the history stack. The `back` input action is automatically wired up to navigate back down the history stack.

By default, every time you navigate to a new route, the application focus will be automatically passed to the newly loaded page. If you instead want to maintain the current focus (for example in a widget that sits above your RouterView), you can use `passFocus: false` as part of the router options.

## Deeplinking

The Router plugin has support for deeplinking. When the App is loaded with a URL hash (i.e. `#/pages/settings/network`), the router will try to match that hash to a defined route. This means that your app can be deep linked into, by simply providing the correct URL hash.
Expand Down
13 changes: 4 additions & 9 deletions docs/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,6 @@
}
]
},
{
"text": "Performance",
"items": [
{
"text": "Lazy Loading",
"link": "/performance/lazy-loading"
}
]
},
{
"text": "Router",
"items": [
Expand Down Expand Up @@ -156,6 +147,10 @@
{
"text": "Global App State",
"link": "/plugins/global_app_state"
},
{
"text": "Storage",
"link": "/plugins/storage"
}
]
},
Expand Down
27 changes: 25 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,30 @@ declare module '@lightningjs/blits' {

// todo: specify valid route options
export interface RouteOptions {
[key: string]: any
/**
* Whether the page navigation should be added to the history stack
* used when navigating back using `this.$router.back()`
*
* @default true
*/
inHistory?: Boolean
/**
* Whether the page should be kept alive when navigating away. Can be useful
* for a homepage where the state should be fully retained when navigating back
* from a details page
*
* @default false
*/
keepAlive?: Boolean
/**
* Whether the focus should be delegated to the page that's being navigated to.
* Can be useful when navigating to a new page from a widget / menu overlaying the
* RouterView, where the widget should maintain the focus (instead of the new page, which
* is the default behaviour)
*
* @default true
*/
passFocus?: Boolean
}

export interface Router {
Expand Down Expand Up @@ -628,7 +651,7 @@ declare module '@lightningjs/blits' {
/**
* Extra route options
*/
options?: object // todo: specify which options are available,
options?: RouteOptions
/**
* Message to be announced when visiting the route (often used for accessibility purposes)
*
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lightningjs/blits",
"version": "1.35.5",
"version": "1.36.0",
"description": "Blits: The Lightning 3 App Development Framework",
"bin": "bin/index.js",
"exports": {
Expand Down
21 changes: 15 additions & 6 deletions src/announcer/announcer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Log } from '../lib/log.js'
import speechSynthesis from './speechSynthesis.js'

let active = false
Expand All @@ -28,6 +29,7 @@ const noopAnnouncement = {
then() {},
done() {},
cancel() {},
remove() {},
stop() {},
}

Expand Down Expand Up @@ -66,11 +68,11 @@ const addToQueue = (message, politeness, delay = false) => {
resolveFn = resolve
})

// augment the promise with a cancel function
done.cancel = () => {
// augment the promise with a cancel / remove function
done.remove = done.cancel = () => {
const index = queue.findIndex((item) => item.id === id)
if (index !== -1) queue.splice(index, 1)
isProcessing = false
Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`)
resolveFn('canceled')
}

Expand All @@ -92,6 +94,8 @@ const addToQueue = (message, politeness, delay = false) => {
queue.push({ delay, resolveFn, id })
}

Log.debug(`Announcer - added to queue: "${message}" (id: ${id})`)

setTimeout(() => {
processQueue()
}, 100)
Expand All @@ -118,17 +122,22 @@ const processQueue = async () => {
if (debounce !== null) clearTimeout(debounce)
// add some easing when speaking the messages to reduce stuttering
debounce = setTimeout(() => {
Log.debug(`Announcer - speaking: "${message}" (id: ${id})`)

speechSynthesis
.speak({ message })
.speak({ message, id })
.then(() => {
isProcessing = false
Log.debug(`Announcer - finished speaking: "${message}" (id: ${id})`)

currentId = null
isProcessing = false
resolveFn('finished')
processQueue()
})
.catch((e) => {
isProcessing = false
currentId = null
isProcessing = false
Log.debug(`Announcer - error ("${e.error}") while speaking: "${message}" (id: ${id})`)
resolveFn(e.error)
processQueue()
})
Expand Down
2 changes: 1 addition & 1 deletion src/announcer/speechSynthesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const initialize = () => {

const speak = (options) => {
const utterance = new SpeechSynthesisUtterance(options.message)
const id = Date.now() + Math.random() // Unique ID for tracking
const id = options.id
utterance.lang = options.lang || defaultUtteranceProps.lang
utterance.pitch = options.pitch || defaultUtteranceProps.pitch
utterance.rate = options.rate || defaultUtteranceProps.rate
Expand Down
6 changes: 4 additions & 2 deletions src/router/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,10 @@ export const navigate = async function () {
const children = this[symbols.children]
this.activeView = children[children.length - 1]

// set focus to the view that we're routing to
focus ? focus.$focus() : /** @type {BlitsComponent} */ (view).$focus()
// set focus to the view that we're routing to (unless explicitly disabling passing focus)
if (route.options.passFocus !== false) {
focus ? focus.$focus() : /** @type {BlitsComponent} */ (view).$focus()
}

// apply before settings to holder element
if (route.transition.before) {
Expand Down