@fusion.dev/helix-core 0.222.0 → 0.223.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.
@@ -20,6 +20,8 @@ export declare class VoiceElement {
20
20
  stopListening(): void;
21
21
  /** The dictation button and its status, behind a seam a tier can move. */
22
22
  protected renderVoice(): TemplateResult | typeof nothing;
23
+ /** What the dictation button draws: the microphone, or a level meter while listening. */
24
+ protected renderVoiceGlyph(): TemplateResult;
23
25
  /** The native field dictation types into. */
24
26
  protected voiceField(): HTMLInputElement | HTMLTextAreaElement | null;
25
27
  /** The type of the field dictation types into. Dictation listens only in `text`, `search`, `tel` and `url`. */
@@ -1,7 +1,8 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { microphone } from '@fusion.dev/helix-icons';
3
- import { html, nothing } from 'lit';
3
+ import { nothing } from 'lit';
4
4
  import { property, state } from 'lit/decorators.js';
5
+ import { html } from 'lit/static-html.js';
5
6
  import { HelixBeforeListenEvent, HelixListenEvent } from '../../events/events.js';
6
7
  import { drawIcon } from '../../utils/draw-icon/draw-icon.js';
7
8
  import { pageSpeechEngine, } from '../../utils/speech/speech.js';
@@ -101,6 +102,10 @@ export const MixinVoice = (Base) => {
101
102
  final: (text) => this.place(text, true),
102
103
  level: (level) => {
103
104
  this.style.setProperty('--dictation-level', level.toFixed(3));
105
+ const meter = this.partNamed('voice-level');
106
+ if (meter) {
107
+ meter.level = level;
108
+ }
104
109
  },
105
110
  partial: (text) => this.place(text, false),
106
111
  },
@@ -170,6 +175,14 @@ export const MixinVoice = (Base) => {
170
175
  this.dispatchEvent(new HelixListenEvent({ text }));
171
176
  }
172
177
  }
178
+ renderVoiceGlyph() {
179
+ const tier = this.constructor.tier;
180
+ if (this.heard && customElements.get(`${tier}voice-level`)) {
181
+ const meter = this.tag('voice-level');
182
+ return html `<${meter} part="voice-level" exportparts="canvas: voice-level-canvas" aria-hidden="true" variant="spectrum"></${meter}>`;
183
+ }
184
+ return drawIcon(microphone);
185
+ }
173
186
  renderVoice() {
174
187
  if (!this.voice || !this.voiceReady) {
175
188
  return nothing;
@@ -191,7 +204,7 @@ export const MixinVoice = (Base) => {
191
204
  }
192
205
  }}
193
206
  >
194
- ${drawIcon(microphone)}
207
+ ${this.renderVoiceGlyph()}
195
208
  </button
196
209
  ><span part="voice-status" data-spoken role="status">${this.said}</span>`;
197
210
  }
@@ -42,9 +42,10 @@ export interface SpeechEngine {
42
42
  * where the browser offers one. Chrome's service is Google's, and Chromium browsers without Google's
43
43
  * keys, such as Brave, reach no service at all and end with `network`.
44
44
  *
45
- * `meter` reads loudness for the ring. Leave it off where this page is
46
- * listening for a frame. A second capture of the microphone ends the
47
- * recognizer, and the prompt the reader sees belongs to that capture.
45
+ * `meter` reads loudness for the dictation button's level from a second
46
+ * capture of the microphone, opened on the recognizer's `audiostart`. Opened
47
+ * at the same time as the recognizer, that capture ended recognition after the
48
+ * permission prompt. Turn it off with `meter: false`.
48
49
  */
49
50
  export declare const recognizeSpeech: (lang: string, listener: SpeechListener, options?: {
50
51
  meter?: boolean;
@@ -96,9 +96,15 @@ export const recognizeSpeech = (lang, listener, options) => {
96
96
  let asked = false;
97
97
  let ended = false;
98
98
  let recognition;
99
- const quiet = options?.meter === false
100
- ? () => { }
101
- : meter((level, bands) => listener.level?.(level, bands));
99
+ let quiet = () => { };
100
+ let metering = false;
101
+ const startMeter = () => {
102
+ if (options?.meter === false || metering || ended) {
103
+ return;
104
+ }
105
+ metering = true;
106
+ quiet = meter((level, bands) => listener.level?.(level, bands));
107
+ };
102
108
  const end = (reason, message) => {
103
109
  if (ended) {
104
110
  return;
@@ -119,6 +125,7 @@ export const recognizeSpeech = (lang, listener, options) => {
119
125
  }
120
126
  let failed;
121
127
  let heard = false;
128
+ current.onaudiostart = startMeter;
122
129
  current.onresult = (event) => {
123
130
  heard = true;
124
131
  let guess = '';
package/dist/version.d.ts CHANGED
@@ -6,4 +6,4 @@
6
6
  * release, so the two never disagree; a spec beside this holds them to it.
7
7
  * Nothing else in the running code knows which release it is.
8
8
  */
9
- export declare const VERSION = "0.222.0";
9
+ export declare const VERSION = "0.223.1";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.222.0';
1
+ export const VERSION = '0.223.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-core",
3
3
  "description": "Helix element primitives: base classes, mixins, decorators, utilities.",
4
- "version": "0.222.0",
4
+ "version": "0.223.1",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -81,12 +81,12 @@
81
81
  "bugs": "https://github.com/project-fusion/fusion/issues",
82
82
  "dependencies": {
83
83
  "@floating-ui/dom": "^1.8.0",
84
- "@fusion.dev/helix-icons": "0.222.0",
84
+ "@fusion.dev/helix-icons": "0.223.1",
85
85
  "tslib": "^2.8.1"
86
86
  },
87
87
  "devDependencies": {
88
- "@fusion.dev/helix-cem": "0.222.0",
89
- "@fusion.dev/helix-testing": "0.222.0",
88
+ "@fusion.dev/helix-cem": "0.223.1",
89
+ "@fusion.dev/helix-testing": "0.223.1",
90
90
  "@lit-labs/ssr": "^4.1.0",
91
91
  "lit": "^3.2.1"
92
92
  },