@burdenoff/website-sdk 2026.828.5 → 2026.828.6
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/dist/components/explore.d.mts +11 -1
- package/dist/components/explore.d.ts +11 -1
- package/dist/components/explore.js +175 -57
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +175 -58
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.js +104 -41
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +104 -41
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.js +174 -57
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/hooks/index.mjs
CHANGED
|
@@ -1276,11 +1276,42 @@ function getRecognitionCtor() {
|
|
|
1276
1276
|
const w = window;
|
|
1277
1277
|
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
1278
1278
|
}
|
|
1279
|
+
var MIC_DENIED_MESSAGE = "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
1280
|
+
async function ensureMicrophoneAccess() {
|
|
1281
|
+
const media = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
1282
|
+
if (!media?.getUserMedia) return { ok: true };
|
|
1283
|
+
try {
|
|
1284
|
+
const status = await navigator.permissions?.query({
|
|
1285
|
+
name: "microphone"
|
|
1286
|
+
});
|
|
1287
|
+
if (status?.state === "granted") return { ok: true };
|
|
1288
|
+
if (status?.state === "denied")
|
|
1289
|
+
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
1290
|
+
} catch {
|
|
1291
|
+
}
|
|
1292
|
+
try {
|
|
1293
|
+
const stream = await media.getUserMedia({ audio: true });
|
|
1294
|
+
for (const track of stream.getTracks()) track.stop();
|
|
1295
|
+
return { ok: true };
|
|
1296
|
+
} catch (error) {
|
|
1297
|
+
const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
|
|
1298
|
+
if (name === "NotAllowedError" || name === "SecurityError") {
|
|
1299
|
+
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
1300
|
+
}
|
|
1301
|
+
if (name === "NotFoundError" || name === "DevicesNotFoundError") {
|
|
1302
|
+
return { ok: false, message: "No microphone was found." };
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
ok: false,
|
|
1306
|
+
message: "Dictation could not start. You can type instead."
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1279
1310
|
function describeError(code) {
|
|
1280
1311
|
switch (code) {
|
|
1281
1312
|
case "not-allowed":
|
|
1282
1313
|
case "service-not-allowed":
|
|
1283
|
-
return
|
|
1314
|
+
return MIC_DENIED_MESSAGE;
|
|
1284
1315
|
case "no-speech":
|
|
1285
1316
|
return "I didn't catch anything \u2014 try again a little closer to the mic.";
|
|
1286
1317
|
case "audio-capture":
|
|
@@ -1303,11 +1334,22 @@ function useSpeechInput({
|
|
|
1303
1334
|
const [interim, setInterim] = useState("");
|
|
1304
1335
|
const [error, setError] = useState(null);
|
|
1305
1336
|
const recognitionRef = useRef(null);
|
|
1337
|
+
const startTokenRef = useRef(0);
|
|
1338
|
+
const beginRecognitionRef = useRef(null);
|
|
1339
|
+
const beginRecognition = useCallback(
|
|
1340
|
+
(Ctor, token) => {
|
|
1341
|
+
beginRecognitionRef.current?.(Ctor, token);
|
|
1342
|
+
},
|
|
1343
|
+
[]
|
|
1344
|
+
);
|
|
1306
1345
|
const finalRef = useRef(onFinalTranscript);
|
|
1307
1346
|
const errorRef = useRef(onError);
|
|
1308
1347
|
finalRef.current = onFinalTranscript;
|
|
1309
1348
|
errorRef.current = onError;
|
|
1310
1349
|
const stop = useCallback(() => {
|
|
1350
|
+
startTokenRef.current += 1;
|
|
1351
|
+
setListening(false);
|
|
1352
|
+
setInterim("");
|
|
1311
1353
|
const recognition = recognitionRef.current;
|
|
1312
1354
|
if (!recognition) return;
|
|
1313
1355
|
try {
|
|
@@ -1321,48 +1363,69 @@ function useSpeechInput({
|
|
|
1321
1363
|
const Ctor = getRecognitionCtor();
|
|
1322
1364
|
if (!Ctor) return;
|
|
1323
1365
|
if (recognitionRef.current) stop();
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
let pending = "";
|
|
1336
|
-
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1337
|
-
const result = event.results[i];
|
|
1338
|
-
if (!result) continue;
|
|
1339
|
-
const text = result[0]?.transcript ?? "";
|
|
1340
|
-
if (result.isFinal) settled += text;
|
|
1341
|
-
else pending += text;
|
|
1366
|
+
setError(null);
|
|
1367
|
+
setListening(true);
|
|
1368
|
+
startTokenRef.current += 1;
|
|
1369
|
+
const token = startTokenRef.current;
|
|
1370
|
+
void ensureMicrophoneAccess().then((access) => {
|
|
1371
|
+
if (token !== startTokenRef.current) return;
|
|
1372
|
+
if (!access.ok) {
|
|
1373
|
+
setListening(false);
|
|
1374
|
+
setError(access.message);
|
|
1375
|
+
errorRef.current?.(access.message);
|
|
1376
|
+
return;
|
|
1342
1377
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1378
|
+
beginRecognition(Ctor, token);
|
|
1379
|
+
});
|
|
1380
|
+
}, [beginRecognition, stop]);
|
|
1381
|
+
const beginRecognitionImpl = useCallback(
|
|
1382
|
+
(Ctor, token) => {
|
|
1383
|
+
const recognition = new Ctor();
|
|
1384
|
+
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1385
|
+
recognition.continuous = true;
|
|
1386
|
+
recognition.interimResults = true;
|
|
1387
|
+
recognition.maxAlternatives = 1;
|
|
1388
|
+
recognition.onstart = () => {
|
|
1389
|
+
if (token !== startTokenRef.current) return;
|
|
1390
|
+
setError(null);
|
|
1391
|
+
setListening(true);
|
|
1392
|
+
};
|
|
1393
|
+
recognition.onresult = (event) => {
|
|
1394
|
+
let settled = "";
|
|
1395
|
+
let pending = "";
|
|
1396
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1397
|
+
const result = event.results[i];
|
|
1398
|
+
if (!result) continue;
|
|
1399
|
+
const text = result[0]?.transcript ?? "";
|
|
1400
|
+
if (result.isFinal) settled += text;
|
|
1401
|
+
else pending += text;
|
|
1402
|
+
}
|
|
1403
|
+
setInterim(pending);
|
|
1404
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
1405
|
+
};
|
|
1406
|
+
recognition.onerror = (event) => {
|
|
1407
|
+
const message = describeError(event.error);
|
|
1408
|
+
setListening(false);
|
|
1409
|
+
setInterim("");
|
|
1410
|
+
if (message !== "") {
|
|
1411
|
+
setError(message);
|
|
1412
|
+
errorRef.current?.(message);
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
recognition.onend = () => {
|
|
1416
|
+
setListening(false);
|
|
1417
|
+
setInterim("");
|
|
1418
|
+
};
|
|
1419
|
+
recognitionRef.current = recognition;
|
|
1420
|
+
try {
|
|
1421
|
+
recognition.start();
|
|
1422
|
+
} catch {
|
|
1423
|
+
setListening(false);
|
|
1353
1424
|
}
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
};
|
|
1359
|
-
recognitionRef.current = recognition;
|
|
1360
|
-
try {
|
|
1361
|
-
recognition.start();
|
|
1362
|
-
} catch {
|
|
1363
|
-
setListening(false);
|
|
1364
|
-
}
|
|
1365
|
-
}, [lang, stop]);
|
|
1425
|
+
},
|
|
1426
|
+
[lang]
|
|
1427
|
+
);
|
|
1428
|
+
beginRecognitionRef.current = beginRecognitionImpl;
|
|
1366
1429
|
const toggle = useCallback(() => {
|
|
1367
1430
|
if (listening) stop();
|
|
1368
1431
|
else start();
|