dictate-button 1.8.0 → 1.9.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.
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
- # Dictate Button (Web Component)
1
+ # Dictate Button
2
2
  ![NPM Version](https://img.shields.io/npm/v/dictate-button)
3
+ [![Tests](https://github.com/dictate-button/dictate-button/actions/workflows/test.yml/badge.svg)](https://github.com/dictate-button/dictate-button/actions/workflows/test.yml)
3
4
 
4
5
  A customizable web component that adds speech-to-text dictation capabilities to any text input, textarea field, or contenteditable element on your website.
5
6
 
@@ -46,10 +47,9 @@ Both auto-inject modes:
46
47
 
47
48
  #### Option 1: Using the exclusive auto-inject script
48
49
 
49
- In your HTML `<head>` tag, add the following script tags:
50
+ In your HTML `<head>` tag, add the following script tag:
50
51
 
51
52
  ```html
52
- <script type="module" crossorigin src="https://cdn.dictate-button.io/dictate-button.js"></script>
53
53
  <script type="module" crossorigin src="https://cdn.dictate-button.io/inject-exclusive.js"></script>
54
54
  ```
55
55
 
@@ -65,10 +65,9 @@ Add the `data-dictate-button-on` attribute to any `textarea`, `input[type="text"
65
65
 
66
66
  #### Option 2: Using the inclusive auto-inject script
67
67
 
68
- In your HTML `<head>` tag, add the following script tags:
68
+ In your HTML `<head>` tag, add the following script tag:
69
69
 
70
70
  ```html
71
- <script type="module" crossorigin src="https://cdn.dictate-button.io/dictate-button.js"></script>
72
71
  <script type="module" crossorigin src="https://cdn.dictate-button.io/inject-inclusive.js"></script>
73
72
  ```
74
73
 
@@ -96,15 +95,7 @@ Import the component and use it directly in your code:
96
95
 
97
96
  ### From NPM
98
97
 
99
- Import once for your app.
100
-
101
- The button component:
102
-
103
- ```js
104
- import 'dictate-button'
105
- ```
106
-
107
- The auto-inject script:
98
+ Import once for your app:
108
99
 
109
100
  ```js
110
101
  // For selected text fields (with data-dictate-button-on attribute):
@@ -123,6 +114,7 @@ Tip: You can also import from subpaths (e.g., 'dictate-button/libs/injectDictate
123
114
  for smaller bundles, if your bundler resolves package subpath exports.
124
115
 
125
116
  ```js
117
+ import 'dictate-button' // Required when using library functions directly
126
118
  import { injectDictateButton, injectDictateButtonOnLoad } from 'dictate-button/libs'
127
119
 
128
120
  // Inject dictate buttons immediately to matching elements
@@ -162,6 +154,12 @@ The dictate-button component emits the following events:
162
154
  - `transcribing:finished`: Fired when transcribing is complete. The event detail contains the transcribed text.
163
155
  - `transcribing:failed`: Fired when an error occurs during transcribing.
164
156
 
157
+ The ideal scenario is when user first starts recording (`recording:started`), then stops recording (`recording:stopped`), then the recorded audio is sent to the server for processing (`transcribing:started`), and finally the transcribed text is received (`transcribing:finished`).
158
+
159
+ > recording:started -> recording:stopped -> transcribing:started -> transcribing:finished
160
+
161
+ In case of an error in recording or transcribing, the `recording:failed` or `transcribing:failed` event is fired, respectively.
162
+
165
163
  Example event handling:
166
164
 
167
165
  ```javascript
@@ -215,7 +213,7 @@ You can specify your own endpoint by setting the `apiEndpoint` attribute.
215
213
  The API expects:
216
214
  - POST request
217
215
  - Multipart form data with the following fields:
218
- - `audio`: Audio data as a Blob (audio/webm format)
216
+ - `audio`: Audio data as a File (audio/webm format)
219
217
  - `origin`: The origin of the website (automatically added)
220
218
  - `language`: Optional language code (if provided as an attribute)
221
219
  - Response should be JSON with a `text` property containing the transcribed text
@@ -1,4 +1,4 @@
1
- const St = (t, n) => t === n, j = {
1
+ const St = (t, n) => t === n, I = {
2
2
  equals: St
3
3
  };
4
4
  let pt = _t;
@@ -16,7 +16,7 @@ function At(t, n) {
16
16
  cleanups: null,
17
17
  context: i ? i.context : null,
18
18
  owner: i
19
- }, s = r ? t : () => t(() => V(() => $(l)));
19
+ }, s = r ? t : () => t(() => V(() => L(l)));
20
20
  b = l, g = null;
21
21
  try {
22
22
  return M(s, !0);
@@ -25,7 +25,7 @@ function At(t, n) {
25
25
  }
26
26
  }
27
27
  function gt(t, n) {
28
- n = n ? Object.assign({}, j, n) : j;
28
+ n = n ? Object.assign({}, I, n) : I;
29
29
  const e = {
30
30
  value: t,
31
31
  observers: null,
@@ -36,17 +36,17 @@ function gt(t, n) {
36
36
  }
37
37
  function D(t, n, e) {
38
38
  const o = Z(t, n, !1, x);
39
- L(o);
39
+ $(o);
40
40
  }
41
41
  function kt(t, n, e) {
42
42
  pt = Mt;
43
43
  const o = Z(t, n, !1, x);
44
- o.user = !0, E ? E.push(o) : L(o);
44
+ o.user = !0, E ? E.push(o) : $(o);
45
45
  }
46
46
  function Tt(t, n, e) {
47
- e = e ? Object.assign({}, j, e) : j;
47
+ e = e ? Object.assign({}, I, e) : I;
48
48
  const o = Z(t, n, !0, 0);
49
- return o.observers = null, o.observerSlots = null, o.comparator = e.equals || void 0, L(o), bt.bind(o);
49
+ return o.observers = null, o.observerSlots = null, o.comparator = e.equals || void 0, $(o), bt.bind(o);
50
50
  }
51
51
  function V(t) {
52
52
  if (g === null) return t();
@@ -63,7 +63,7 @@ function Pt(t) {
63
63
  }
64
64
  function bt() {
65
65
  if (this.sources && this.state)
66
- if (this.state === x) L(this);
66
+ if (this.state === x) $(this);
67
67
  else {
68
68
  const t = w;
69
69
  w = null, M(() => K(this), !1), w = t;
@@ -85,20 +85,20 @@ function yt(t, n, e) {
85
85
  throw w = [], new Error();
86
86
  }, !1)), n;
87
87
  }
88
- function L(t) {
88
+ function $(t) {
89
89
  if (!t.fn) return;
90
- $(t);
90
+ L(t);
91
91
  const n = z;
92
- $t(t, t.value, n);
92
+ Lt(t, t.value, n);
93
93
  }
94
- function $t(t, n, e) {
94
+ function Lt(t, n, e) {
95
95
  let o;
96
96
  const r = b, i = g;
97
97
  g = b = t;
98
98
  try {
99
99
  o = t.fn(n);
100
100
  } catch (l) {
101
- return t.pure && (t.state = x, t.owned && t.owned.forEach($), t.owned = null), t.updatedAt = e + 1, vt(l);
101
+ return t.pure && (t.state = x, t.owned && t.owned.forEach(L), t.owned = null), t.updatedAt = e + 1, vt(l);
102
102
  } finally {
103
103
  g = i, b = r;
104
104
  }
@@ -129,7 +129,7 @@ function F(t) {
129
129
  t.state && n.push(t);
130
130
  for (let e = n.length - 1; e >= 0; e--)
131
131
  if (t = n[e], t.state === x)
132
- L(t);
132
+ $(t);
133
133
  else if (t.state === N) {
134
134
  const o = w;
135
135
  w = null, M(() => K(t, n[0]), !1), w = o;
@@ -141,12 +141,12 @@ function M(t, n) {
141
141
  n || (w = []), E ? e = !0 : E = [], z++;
142
142
  try {
143
143
  const o = t();
144
- return Lt(e), o;
144
+ return $t(e), o;
145
145
  } catch (o) {
146
146
  e || (E = null), w = null, vt(o);
147
147
  }
148
148
  }
149
- function Lt(t) {
149
+ function $t(t) {
150
150
  if (w && (_t(w), w = null), t) return;
151
151
  const n = E;
152
152
  E = null, n.length && M(() => pt(n), !1);
@@ -178,7 +178,7 @@ function wt(t) {
178
178
  e.state || (e.state = N, e.pure ? w.push(e) : E.push(e), e.observers && wt(e));
179
179
  }
180
180
  }
181
- function $(t) {
181
+ function L(t) {
182
182
  let n;
183
183
  if (t.sources)
184
184
  for (; t.sources.length; ) {
@@ -189,11 +189,11 @@ function $(t) {
189
189
  }
190
190
  }
191
191
  if (t.tOwned) {
192
- for (n = t.tOwned.length - 1; n >= 0; n--) $(t.tOwned[n]);
192
+ for (n = t.tOwned.length - 1; n >= 0; n--) L(t.tOwned[n]);
193
193
  delete t.tOwned;
194
194
  }
195
195
  if (t.owned) {
196
- for (n = t.owned.length - 1; n >= 0; n--) $(t.owned[n]);
196
+ for (n = t.owned.length - 1; n >= 0; n--) L(t.owned[n]);
197
197
  t.owned = null;
198
198
  }
199
199
  if (t.cleanups) {
@@ -210,10 +210,10 @@ function Ot(t) {
210
210
  function vt(t, n = b) {
211
211
  throw Ot(t);
212
212
  }
213
- function B(t, n) {
213
+ function j(t, n) {
214
214
  return V(() => t(n || {}));
215
215
  }
216
- const I = (t) => Tt(() => t());
216
+ const B = (t) => Tt(() => t());
217
217
  function Rt(t, n, e) {
218
218
  let o = e.length, r = n.length, i = o, l = 0, s = 0, a = n[r - 1].nextSibling, d = null;
219
219
  for (; l < r || s < i; ) {
@@ -264,7 +264,7 @@ function O(t, n, e, o) {
264
264
  function P(t, n, e) {
265
265
  e == null ? t.removeAttribute(n) : t.setAttribute(n, e);
266
266
  }
267
- function Bt(t, n, e) {
267
+ function jt(t, n, e) {
268
268
  if (!n) return e ? P(t, "style") : n;
269
269
  const o = t.style;
270
270
  if (typeof n == "string") return o.cssText = n;
@@ -276,7 +276,7 @@ function Bt(t, n, e) {
276
276
  r = n[i], r !== e[i] && (o.setProperty(i, r), e[i] = r);
277
277
  return e;
278
278
  }
279
- function It(t, n, e) {
279
+ function Bt(t, n, e) {
280
280
  return V(() => t(n, e));
281
281
  }
282
282
  function A(t, n, e, o) {
@@ -361,7 +361,7 @@ function k(t, n, e, o) {
361
361
  } else t.insertBefore(r, e);
362
362
  return [r];
363
363
  }
364
- function jt(t) {
364
+ function It(t) {
365
365
  return Object.keys(t).reduce((e, o) => {
366
366
  const r = t[o];
367
367
  return e[o] = Object.assign({}, r), mt(r.value) && !Ut(r.value) && !Array.isArray(r.value) && (e[o].value = Object.assign({}, r.value)), Array.isArray(r.value) && (e[o].value = r.value.slice(0)), e;
@@ -379,7 +379,7 @@ function Dt(t) {
379
379
  return Object.keys(t).reduce((e, o) => (e[o] = t[o].value, e), {});
380
380
  }
381
381
  function Ft(t, n) {
382
- const e = jt(n);
382
+ const e = It(n);
383
383
  return Object.keys(n).forEach((r) => {
384
384
  const i = e[r], l = t.getAttribute(i.attribute), s = t[r];
385
385
  l != null && (i.value = i.parse ? Ct(l) : l), s != null && (i.value = Array.isArray(s) ? s.slice(0) : s), i.reflect && ct(t, i.attribute, i.value, !!i.parse), Object.defineProperty(t, r, {
@@ -584,9 +584,9 @@ const Xt = `
584
584
  }
585
585
  `;
586
586
  var Zt = /* @__PURE__ */ O('<div part=container class=dictate-button__container><style></style><div aria-live=polite class=dictate-button__status-announcer style="position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></div><button part=button class=dictate-button__button>'), Qt = /* @__PURE__ */ O('<svg part=icon class="dictate-button__icon dictate-button__icon--idle"fill=none viewBox="0 0 24 24"stroke-width=1.5 stroke=currentColor role=img aria-hidden=true><path stroke-linecap=round stroke-linejoin=round d="M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 0 1-3-3V4.5a3 3 0 1 1 6 0v8.25a3 3 0 0 1-3 3Z">'), Yt = /* @__PURE__ */ O('<svg part=icon class="dictate-button__icon dictate-button__icon--recording"viewBox="0 0 24 24"fill=currentColor role=img aria-hidden=true><circle cx=12 cy=12 r=10>'), te = /* @__PURE__ */ O('<svg part=icon class="dictate-button__icon dictate-button__icon--processing"viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round role=img aria-hidden=true><path d="M12 2v4"></path><path d="m16.2 7.8 2.9-2.9"></path><path d="M18 12h4"></path><path d="m16.2 16.2 2.9 2.9"></path><path d="M12 18v4"></path><path d="m4.9 19.1 2.9-2.9"></path><path d="M2 12h4"></path><path d="m4.9 4.9 2.9 2.9">'), ee = /* @__PURE__ */ O('<svg part=icon class="dictate-button__icon dictate-button__icon--error"viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=4 stroke-linecap=round stroke-linejoin=round role=img aria-hidden=true><line x1=12 x2=12 y1=4 y2=14></line><line x1=12 x2=12.01 y1=20 y2=20>');
587
- console.debug("dictate-button version:", "1.8.0");
587
+ console.debug("dictate-button version:", "1.9.0");
588
588
  const ne = "https://api.dictate-button.io/transcribe", S = "dictate-button.io", J = -70, ut = -10, dt = 0, re = 4, oe = 0.25, ie = 0.05;
589
- Jt("dictate-button", {
589
+ customElements.get("dictate-button") ? console.debug("dictate-button: We don't require importing the dictate-button component separately anymore, so you may remove the script tag which imports https://cdn.dictate-button.io/dictate-button.js from the HTML head.") : Jt("dictate-button", {
590
590
  size: 30,
591
591
  apiEndpoint: ne,
592
592
  language: void 0
@@ -679,21 +679,21 @@ Jt("dictate-button", {
679
679
  var f = Zt(), _ = f.firstChild, v = _.nextSibling, u = v.nextSibling;
680
680
  A(_, Xt), A(v, () => ft(e()));
681
681
  var m = R;
682
- return typeof m == "function" ? It(m, u) : R = u, A(u, (() => {
683
- var h = I(() => e() === "idle");
684
- return () => h() && B(le, {});
682
+ return typeof m == "function" ? Bt(m, u) : R = u, A(u, (() => {
683
+ var h = B(() => e() === "idle");
684
+ return () => h() && j(le, {});
685
685
  })(), null), A(u, (() => {
686
- var h = I(() => e() === "recording");
687
- return () => h() && B(ae, {});
686
+ var h = B(() => e() === "recording");
687
+ return () => h() && j(ae, {});
688
688
  })(), null), A(u, (() => {
689
- var h = I(() => e() === "processing");
690
- return () => h() && B(ce, {});
689
+ var h = B(() => e() === "processing");
690
+ return () => h() && j(ce, {});
691
691
  })(), null), A(u, (() => {
692
- var h = I(() => e() === "error");
693
- return () => h() && B(ue, {});
692
+ var h = B(() => e() === "error");
693
+ return () => h() && j(ue, {});
694
694
  })(), null), D((h) => {
695
695
  var H = `width:${t.size}px;height:${t.size}px"`, ot = se(e()), it = ft(e()), st = e() === "recording", lt = e() === "processing";
696
- return h.e = Bt(u, H, h.e), ot !== h.t && P(u, "title", h.t = ot), it !== h.a && P(u, "aria-label", h.a = it), st !== h.o && P(u, "aria-pressed", h.o = st), lt !== h.i && P(u, "aria-busy", h.i = lt), h;
696
+ return h.e = jt(u, H, h.e), ot !== h.t && P(u, "title", h.t = ot), it !== h.a && P(u, "aria-label", h.a = it), st !== h.o && P(u, "aria-pressed", h.o = st), lt !== h.i && P(u, "aria-busy", h.i = lt), h;
697
697
  }, {
698
698
  e: void 0,
699
699
  t: void 0,
File without changes
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +1,4 @@
1
+ import "./dictate-button.js";
1
2
  import { injectDictateButtonOnLoad as t } from "./libs/injectDictateButtonOnLoad.js";
2
3
  const a = 30, n = !0, e = !1, o = [
3
4
  "textarea[data-dictate-button-on]:not([data-dictate-button-enabled])",
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +1,4 @@
1
+ import "./dictate-button.js";
1
2
  import { injectDictateButtonOnLoad as t } from "./libs/injectDictateButtonOnLoad.js";
2
3
  const a = 30, n = !0, o = !1, e = [
3
4
  "textarea:not([data-dictate-button-off]):not([data-dictate-button-enabled])",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dictate-button",
3
- "version": "1.8.0",
4
- "description": "Dictate Button (Web Component)",
3
+ "version": "1.9.0",
4
+ "description": "Customizable Web Component that adds speech-to-text dictation capabilities to text fields",
5
5
  "keywords": [
6
6
  "custom-element",
7
7
  "dictate",
@@ -60,15 +60,20 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "solid-element": "^1.9.1",
63
- "solid-js": "^1.9.9"
63
+ "solid-js": "^1.9.10"
64
64
  },
65
65
  "devDependencies": {
66
+ "@solidjs/testing-library": "^0.8.10",
67
+ "@testing-library/user-event": "^14.6.1",
68
+ "@vitest/ui": "^4.0.10",
69
+ "jsdom": "^27.2.0",
66
70
  "prettier": "^3.6.2",
67
71
  "typescript": "^5.9.3",
68
- "vite": "^7.1.10",
72
+ "vite": "^7.2.2",
69
73
  "vite-plugin-dts": "^4.5.4",
70
- "vite-plugin-solid": "^2.11.9",
71
- "vite-plugin-static-copy": "^3.1.4"
74
+ "vite-plugin-solid": "^2.11.10",
75
+ "vite-plugin-static-copy": "^3.1.4",
76
+ "vitest": "^4.0.10"
72
77
  },
73
78
  "homepage": "https://github.com/dictate-button/dictate-button",
74
79
  "repository": {
@@ -81,6 +86,9 @@
81
86
  "scripts": {
82
87
  "build": "vite build",
83
88
  "format": "prettier --write './src/**/*.{js,jsx,ts,tsx}'",
84
- "deploy": "firebase deploy"
89
+ "deploy": "firebase deploy",
90
+ "test": "vitest run",
91
+ "test:watch": "vitest",
92
+ "test:ui": "vitest --ui"
85
93
  }
86
94
  }