@appsbd/vue3-appsbd-ui 1.0.15 → 1.0.16
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/.ai/ai_ref_AbChatInput.md +69 -13
- package/.ai/ai_ref_AbVoiceButton.md +112 -0
- package/.ai/ai_ref_migration_guide.md +2 -1
- package/AI_REFERENCE.md +1 -0
- package/CHANGELOG.md +17 -0
- package/dist/style.css +1 -1
- package/dist/vue3-appsbd-ui.cjs.js +80 -85
- package/dist/vue3-appsbd-ui.es.js +8693 -8512
- package/package.json +1 -1
|
@@ -89,21 +89,57 @@ a native file picker and routes the selection through `addFiles`) among other me
|
|
|
89
89
|
Uses the browser's native Web Speech API (`SpeechRecognition`) — no extra dependency, no API key. A built-in mic
|
|
90
90
|
button renders in the `right` area (before the `right` slot and the send button) whenever `showVoiceButton` is
|
|
91
91
|
`true` (default).
|
|
92
|
-
Clicking it (or calling `startRecording()`) swaps the whole composer row for a full-width recording bar — a live
|
|
93
|
-
audio-reactive waveform (via `getUserMedia` + `AnalyserNode`) plus three controls:
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
The composer layout never changes while recording, on every platform — no full-width recording bar swap: the
|
|
94
|
+
textarea stays visible **and stays fully editable** (typing/deleting mid-recording works normally) and fills with
|
|
95
|
+
the transcribed text live as it's recognized. The mic button shows a Google Assistant-style listening cue: its
|
|
96
|
+
circle fills with the theme's primary color (icon turns white to read against it), with a few rings pulsing
|
|
97
|
+
outward from behind it on a loop (`.apbd-chat-input__voice-ring`, staggered so they overlap continuously). Clicking
|
|
98
|
+
it (or calling `stopRecording()`) stops and keeps the text — there's no dedicated cancel button in this UI
|
|
99
|
+
(`cancelRecording()` is still available programmatically via a template ref), and the default send button (or
|
|
100
|
+
`submit()`/Enter generally) stops recording first when called mid-listening, then fires `submit` immediately.
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
On every platform, the textarea is refocused automatically the moment listening ends (stop, cancel, or a
|
|
103
|
+
voice-triggered submit) — the cursor lands right back in it so the user can keep typing without an extra tap.
|
|
104
|
+
|
|
105
|
+
Recognized speech is appended to the existing `modelValue` (not replaced), converting instantly as the user speaks
|
|
106
|
+
on every platform — interim results drive `modelValue` live so the text is already there before the user taps the
|
|
107
|
+
mic to stop, not just once they do (see below).
|
|
101
108
|
|
|
102
109
|
A small language-code badge (e.g. `EN`, `BN`) sits on the mic button's corner. Clicking it opens an `AbPopover`
|
|
103
110
|
with a searchable list of ~130 BCP-47 locales; picking one sets that recognition session's `SpeechRecognition.lang`
|
|
104
111
|
and persists the choice to `localStorage` (key `apbd-chat-input-voice-lang`) so it's remembered next visit. This
|
|
105
112
|
never touches the browser's own language/locale settings — only this component's own recognizer instance.
|
|
106
113
|
|
|
114
|
+
### Voice punctuation
|
|
115
|
+
|
|
116
|
+
Two independent behaviors, each its own boolean prop, **both default `true`**:
|
|
117
|
+
|
|
118
|
+
- **`voicePunctuationCommands`** — saying a punctuation word inserts the actual mark, same idea as Google/Apple
|
|
119
|
+
dictation: English `"period"`/`"full stop"` → `.`, `"comma"` → `,`, `"question mark"` → `?`; Bengali
|
|
120
|
+
`"পূর্ণচ্ছেদ"` → `।`, `"কমা"` → `,`, `"প্রশ্নবোধক"` → `?`. Matched against the recognized transcript text itself
|
|
121
|
+
(not `voiceLang`), so it works regardless of which recognition language is selected. Matching uses
|
|
122
|
+
script-agnostic lookaround (not `\b`, which only understands ASCII letters — a no-op for Bengali) so a command
|
|
123
|
+
word only triggers standalone, never as a substring of a longer word (e.g. saying "দাঁড়িপাল্লা" doesn't trigger
|
|
124
|
+
on the "দাড়ি" inside it). `"দাড়ি"` itself (an earlier alternate trigger, same meaning as `"পূর্ণচ্ছেদ"`) was
|
|
125
|
+
dropped entirely rather than just boundary-guarded — it's also ordinary vocabulary (beard), so a sentence
|
|
126
|
+
actually about a beard would still lose that word every time. `"কমা"` keeps a similar, smaller risk (it's also
|
|
127
|
+
a common verb, "to decrease") — left as-is, since removing every word with *any* plausible double meaning
|
|
128
|
+
would leave nothing left to trigger on.
|
|
129
|
+
- **`voiceAutoPunctuate`** — when a new utterance is about to be appended onto existing text, a sentence-ending
|
|
130
|
+
mark is inserted first if the existing text doesn't already end with one — `.` normally, `।` when `voiceLang`
|
|
131
|
+
starts with `bn`. Applies between pauses (each per-utterance restart, see below), not mid-utterance.
|
|
132
|
+
|
|
133
|
+
Set either to `false` to disable it independently; both keep working with the default Web Speech transcript as-is
|
|
134
|
+
when off.
|
|
135
|
+
|
|
136
|
+
Both also auto-capitalize the sentence start they create: `voiceAutoPunctuate` capitalizes the first letter of a
|
|
137
|
+
new utterance right after it inserts a boundary mark (and always capitalizes the very first letter of the whole
|
|
138
|
+
message, regardless of this prop); `voicePunctuationCommands` capitalizes the letter right after any mark it
|
|
139
|
+
inserts mid-utterance (`"hello period how are you"` → `"Hello. How are you"`). Same script-agnostic approach as the
|
|
140
|
+
punctuation matching above — plain `toUpperCase()` on the matched letter, which is a no-op for scripts without a
|
|
141
|
+
case concept (Bengali, Arabic, CJK, …), so it needs no per-language list.
|
|
142
|
+
|
|
107
143
|
Not supported in Firefox. On iOS, only Safari itself gets it — Chrome/Firefox/Edge/Opera on iOS run on the same
|
|
108
144
|
underlying WebKit engine and expose the same `webkitSpeechRecognition` constructor, but iOS never grants the mic
|
|
109
145
|
permission for it outside of Safari's own app (no permission prompt ever appears; `.start()` would otherwise fail
|
|
@@ -111,10 +147,28 @@ with a confusing, prompt-less "permission denied"), so these are detected via us
|
|
|
111
147
|
too. The mic button still renders in all of these cases but is `disabled`, with a tooltip explaining why. Where it
|
|
112
148
|
is supported, requires the browser's mic permission prompt to be accepted.
|
|
113
149
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
Some browsers/builds hold back `isFinal` results until `.stop()` is called instead of firing them per pause segment
|
|
151
|
+
— waiting for that would mean the transcript only shows up once the user taps stop, not while they're actually
|
|
152
|
+
speaking (and on some builds it never reliably fires at all). `interimResults` is on by default to sidestep that,
|
|
153
|
+
converting speech to text instantly instead of only once recording stops — **except on Safari** (desktop and iOS
|
|
154
|
+
both), where it's kept `false`: Safari's engine has a bug where enabling it can fail to (re)start the recognizer
|
|
155
|
+
entirely, surfacing as a generic "Microphone permission denied" error indistinguishable from an actually-denied
|
|
156
|
+
permission. Safari still converts per finished phrase (not mid-utterance), just not keystroke-by-keystroke live.
|
|
157
|
+
|
|
158
|
+
`continuous`+`interimResults` together is also unreliable across browsers/builds in a way delta-tracking
|
|
159
|
+
`e.results` (via `resultIndex` or position) can't fully work around — it's been observed restating/duplicating
|
|
160
|
+
earlier words in a later result with no restart involved at all. So `recognition.continuous` is always `false` —
|
|
161
|
+
each internal session covers exactly one utterance, and a transparent onend-restart (also covers Safari's own
|
|
162
|
+
quirk of ending a `continuous: true` session early) picks the next utterance back up automatically, so it still
|
|
163
|
+
reads as continuous listening. Within one utterance's `onresult`, only the latest `e.results` entry is read — no
|
|
164
|
+
cross-event bookkeeping needed, since there's nothing earlier in that same array to conflict with.
|
|
165
|
+
|
|
166
|
+
Because the textarea stays editable during recording, `onresult` can't just privately accumulate a running
|
|
167
|
+
transcript either — that would silently clobber whatever the user just typed or deleted. Instead it reads the
|
|
168
|
+
current `modelValue`, strips back off the exact suffix it itself inserted last time (if that suffix is still there
|
|
169
|
+
untouched), and rebuilds from that stable base with the freshly recognized text appended; if the suffix isn't
|
|
170
|
+
there anymore, whatever's currently in the field — including the user's edit — becomes the new base instead of
|
|
171
|
+
being overwritten.
|
|
118
172
|
|
|
119
173
|
## Props
|
|
120
174
|
|
|
@@ -140,6 +194,8 @@ user-agent, not feature-tested.
|
|
|
140
194
|
| `filePreviewHeight` | `Number` | `24` | Height (px) of each attached file's thumbnail/icon in the chip. |
|
|
141
195
|
| `showFileName` | `Boolean` | `true` | Show/hide the filename text next to the chip thumbnail. |
|
|
142
196
|
| `showVoiceButton` | `Boolean` | `true` | Show/hide the built-in mic button (see "Voice input" below). Set `false` to build custom voice UI via slots instead. |
|
|
197
|
+
| `voicePunctuationCommands` | `Boolean` | `true` | Say a punctuation word (e.g. "period", "পূর্ণচ্ছেদ") to insert the actual mark — see "Voice punctuation" above. |
|
|
198
|
+
| `voiceAutoPunctuate` | `Boolean` | `true` | Auto-insert a sentence-ending mark between voice utterances when one isn't already there — see "Voice punctuation" above. |
|
|
143
199
|
|
|
144
200
|
## Events
|
|
145
201
|
|
|
@@ -154,8 +210,8 @@ user-agent, not feature-tested.
|
|
|
154
210
|
| `file-remove` | `FileEntry` | A file chip's remove button was clicked. |
|
|
155
211
|
| `file-reject` | `{ file: File, reason: string }` | A file failed `maxFileSize`/`allowedExtensions` validation. A `useToast` error is also shown. |
|
|
156
212
|
| `voice-start` | — | Voice recording started (mic button clicked or `startRecording()` called). |
|
|
157
|
-
| `voice-stop` | — | Recording stopped normally (
|
|
158
|
-
| `voice-cancel` | — | Recording was cancelled
|
|
213
|
+
| `voice-stop` | — | Recording stopped normally (mic button tapped again, `stopRecording()`, or the browser ending it on its own) — transcribed text is kept in `modelValue`. |
|
|
214
|
+
| `voice-cancel` | — | Recording was cancelled via `cancelRecording()` (no dedicated UI button — call it programmatically via a template ref) — `modelValue` is reverted to what it was before recording started. |
|
|
159
215
|
| `voice-error` | `Error \| SpeechRecognitionErrorEvent` | Mic permission was denied, or the recognition engine errored. A `useToast` error is also shown (except benign `no-speech`/`aborted` errors). |
|
|
160
216
|
|
|
161
217
|
## Slots
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# AbVoiceButton — AI Reference
|
|
2
|
+
|
|
3
|
+
A standalone voice-to-text mic button — the same recognition engine and behavior as `AbChatInput`'s built-in mic,
|
|
4
|
+
with no composer attached. Use it to bolt voice input onto any existing input, form field, search box, or custom
|
|
5
|
+
UI via `v-model`; pick `AbChatInput` instead when you need the whole chat composer (textarea, file attachments,
|
|
6
|
+
add/more dropdown) with voice input built in.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Not globally registered — import it explicitly:
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import { AbVoiceButton } from 'vue3-appsbd-ui';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
No extra peer deps beyond the library's own (`@lucide/vue` for the mic icon). Uses the browser's native Web
|
|
17
|
+
Speech API (`SpeechRecognition`) — no dependency, no API key.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```vue
|
|
22
|
+
<template>
|
|
23
|
+
<AbVoiceButton v-model="message" />
|
|
24
|
+
<p>{{ message }}</p>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup>
|
|
28
|
+
import { ref } from 'vue';
|
|
29
|
+
import { AbVoiceButton } from 'vue3-appsbd-ui';
|
|
30
|
+
|
|
31
|
+
const message = ref('');
|
|
32
|
+
</script>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Pin the recognition language explicitly (there's no built-in language picker here, unlike `AbChatInput`'s mic
|
|
36
|
+
button — pass whichever locale your app already knows the user wants):
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<AbVoiceButton v-model="message" lang="bn-BD" />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Behavior
|
|
43
|
+
|
|
44
|
+
Tapping the button (or calling `startRecording()`) starts listening; the mic icon stays the mic icon, but its
|
|
45
|
+
circle fills with the theme's primary color (`--#{prefix}theme`) and the icon turns white, with a few rings
|
|
46
|
+
pulsing outward from behind it on a loop — a Google Assistant-style listening cue, on every platform (same cue,
|
|
47
|
+
same architecture as `AbChatInput`'s built-in mic — this component just has no composer/textarea attached to it).
|
|
48
|
+
Tap it again (or call `stopRecording()`) to stop and keep the text.
|
|
49
|
+
|
|
50
|
+
Recognized speech merges into `modelValue` live as the user speaks, via one internal recognition session per
|
|
51
|
+
utterance (`continuous: false` + `interimResults: true`, restarted transparently between utterances) — on every
|
|
52
|
+
platform except Safari (desktop and iOS both), where `interimResults` is kept `false`: Safari's engine has a bug
|
|
53
|
+
where enabling it can fail to (re)start the recognizer entirely, surfacing as a generic "Microphone permission
|
|
54
|
+
denied" error indistinguishable from an actually-denied permission. Safari still converts per finished phrase, just
|
|
55
|
+
not keystroke-by-keystroke live. Reads the current `modelValue` on each update and replaces only the exact suffix
|
|
56
|
+
it last inserted itself, so external edits to `modelValue` between voice updates (e.g. the consumer's own code, or
|
|
57
|
+
a bound `<textarea>` the user is also typing into) are preserved rather than clobbered.
|
|
58
|
+
|
|
59
|
+
Not supported in Firefox. On iOS, only Safari itself gets it — Chrome/Firefox/Edge/Opera on iOS run on the same
|
|
60
|
+
underlying WebKit engine and expose the same `webkitSpeechRecognition` constructor, but iOS never grants the mic
|
|
61
|
+
permission for it outside of Safari's own app, so these are detected via user-agent and treated as unsupported too
|
|
62
|
+
(button `disabled`, tooltip explains why). Requires the browser's mic permission prompt to be accepted where
|
|
63
|
+
supported.
|
|
64
|
+
|
|
65
|
+
### Voice punctuation
|
|
66
|
+
|
|
67
|
+
Two independent behaviors, each its own boolean prop, **both default `true`** (identical to `AbChatInput`'s):
|
|
68
|
+
|
|
69
|
+
- **`voicePunctuationCommands`** — saying a punctuation word inserts the actual mark: English `"period"`/
|
|
70
|
+
`"full stop"` → `.`, `"comma"` → `,`, `"question mark"` → `?`; Bengali `"পূর্ণচ্ছেদ"` → `।`, `"কমা"` → `,`,
|
|
71
|
+
`"প্রশ্নবোধক"` → `?`. Matched against the transcript text itself, independent of `lang`. Matching uses
|
|
72
|
+
script-agnostic Unicode lookaround (not `\b`, a no-op for Bengali script), so a command word only triggers
|
|
73
|
+
standalone, never as a substring of a longer word.
|
|
74
|
+
- **`voiceAutoPunctuate`** — a sentence-ending mark is inserted between voice utterances when the existing text
|
|
75
|
+
doesn't already end with one — `.` normally, `।` when `lang` (or the auto-detected language) starts with `bn`.
|
|
76
|
+
|
|
77
|
+
## Props
|
|
78
|
+
|
|
79
|
+
| Name | Type | Default | Description |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| `modelValue` | `String` | `""` | Two-way-bound transcribed text. |
|
|
82
|
+
| `disabled` | `Boolean` | `false` | Disables the button. |
|
|
83
|
+
| `size` | `Number` | `40` | Button diameter in px. Icon and listening rings scale with it. |
|
|
84
|
+
| `lang` | `String` | `""` | BCP-47 recognition locale (e.g. `"bn-BD"`). Empty = auto-detect from `document.documentElement.lang` / `navigator.language`. |
|
|
85
|
+
| `voicePunctuationCommands` | `Boolean` | `true` | Say a punctuation word (e.g. "period", "পূর্ণচ্ছেদ") to insert the actual mark — see "Voice punctuation" above. |
|
|
86
|
+
| `voiceAutoPunctuate` | `Boolean` | `true` | Auto-insert a sentence-ending mark between voice utterances when one isn't already there — see "Voice punctuation" above. |
|
|
87
|
+
|
|
88
|
+
## Events
|
|
89
|
+
|
|
90
|
+
| Event | Payload | Description |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `update:modelValue` | `string` | v-model sync. |
|
|
93
|
+
| `voice-start` | — | Voice recording started (mic tapped, or `startRecording()` called). |
|
|
94
|
+
| `voice-stop` | — | Recording stopped normally (mic tapped again, `stopRecording()`, or the browser ending it on its own) — transcribed text is kept in `modelValue`. |
|
|
95
|
+
| `voice-cancel` | — | Recording was cancelled via `cancelRecording()` — `modelValue` is reverted to what it was before recording started. |
|
|
96
|
+
| `voice-error` | `Error \| SpeechRecognitionErrorEvent` | Mic permission was denied, or the recognition engine errored. A `useToast` error is also shown (except benign `no-speech`/`aborted` errors). |
|
|
97
|
+
|
|
98
|
+
## Slots
|
|
99
|
+
|
|
100
|
+
None.
|
|
101
|
+
|
|
102
|
+
## v-model
|
|
103
|
+
|
|
104
|
+
Yes — `modelValue` + `update:modelValue` (string).
|
|
105
|
+
|
|
106
|
+
## Exposed methods
|
|
107
|
+
|
|
108
|
+
| Method | Description |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `startRecording()` | Starts voice input (same as tapping the button). No-op if unsupported/disabled/already recording. |
|
|
111
|
+
| `stopRecording()` | Stops recording, keeping the transcribed text (same as tapping the button again). |
|
|
112
|
+
| `cancelRecording()` | Stops recording and reverts `modelValue` to what it was before recording started. No dedicated UI for this — call it via a template ref. |
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
- New `formatCurrency`/`formatAmount` utils + matching global config keys (`currency`, `currencyPosition`, `thousandSeparator`, `decimalSeparator`, `numberOfDecimals`, `round`) — optional to adopt for consumer-side number/currency formatting.
|
|
27
27
|
- New `AbChatBox` component (wraps `AbChatInput` as a full chat UI) and new `AbScrollbar` exposed scroll methods.
|
|
28
|
-
- `AbFormCheck` checked-state label color and `description-text` truncation CSS fixes; a WordPress `.
|
|
28
|
+
- `AbFormCheck` checked-state label color and `description-text` truncation CSS fixes; a WordPress `.apbd-radio-input-container` margin conflict fix (covers all enhanced variants, not just `card-flat-check`).
|
|
29
|
+
- `AbSidebar` header no longer clamps to a fixed height and top-aligns its content instead of centering — lets multi-line header content grow the header instead of being clipped/centered.
|
|
29
30
|
- Several `AbChatInput` voice-input (Safari/Android/iOS) and narrow-viewport layout fixes.
|
|
30
31
|
|
|
31
32
|
## [1.0.14] - 2026-08-19
|
package/AI_REFERENCE.md
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
| `AbChatInput` | — | ChatGPT-style auto-growing composer with an item-count-driven add/more dropdown, internal file attachment preview, and built-in Web Speech API voice input. | [.ai/ai_ref_AbChatInput.md](./.ai/ai_ref_AbChatInput.md) |
|
|
62
62
|
| `AbChatInputMenuItem` | — | Presentational row (icon/name/description/action) for `AbChatInput`'s add/more dropdown. | [.ai/ai_ref_AbChatInputMenuItem.md](./.ai/ai_ref_AbChatInputMenuItem.md) |
|
|
63
63
|
| `AbChatBox` | — | Full chat conversation container (header, message list, empty/typing states) built on `AbChatInput`; every part is slot-overridable. | [.ai/ai_ref_AbChatBox.md](./.ai/ai_ref_AbChatBox.md) |
|
|
64
|
+
| `AbVoiceButton` | — | Standalone Web Speech API voice-to-text mic button (v-model), no composer attached — same engine as `AbChatInput`'s built-in mic. | [.ai/ai_ref_AbVoiceButton.md](./.ai/ai_ref_AbVoiceButton.md) |
|
|
64
65
|
| `AbDarkModeToggler` | — | Light / dark theme toggle (pairs with `useTheme`). | [.ai/ai_ref_AbDarkModeToggler.md](./.ai/ai_ref_AbDarkModeToggler.md) |
|
|
65
66
|
| `useAlert` | — | Procedural API to trigger SweetAlert-based modal alerts, notifications, and confirmations. | [.ai/ai_ref_useAlert.md](./.ai/ai_ref_useAlert.md) |
|
|
66
67
|
| `abEventBus` / `emitterObj` | — | Lightweight global event bus using `tiny-emitter`. | [.ai/ai_ref_abEventBus.md](./.ai/ai_ref_abEventBus.md) |
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@appsbd/vue3-appsbd-ui` are documented here. Format loosely follows [Keep a Changelog](https://keepachangelog.com/).
|
|
4
4
|
|
|
5
|
+
## [1.0.16] - 2026-08-27
|
|
6
|
+
|
|
7
|
+
- **Fixed**: WordPress theme conflict — `AbFormCheck`'s enhanced (`.apbd-radio-input-container`) checkbox/radio inputs now reset `margin: 0` to counter WordPress's default form-control margin. (Previously targeted `.is-flat-check`, which only covers the `card-flat-check` variant and missed the other enhanced variants.)
|
|
8
|
+
- **Fixed**: `AbSidebar` header (`.apbd-sidebar-header`) no longer clamps to a fixed `min-height`/`max-height` (now `unset`) and aligns its content to the top (`align-items: start` instead of `center`) — the header can grow to fit multi-line content instead of clipping/centering it within a fixed band.
|
|
9
|
+
- **Changed**: `AbChatInput` voice recording on Android only — no longer swaps the composer for the full-width recording bar (every other platform keeps that unchanged: waveform + cancel/stop/submit buttons). On Android the textarea now stays visible and fully editable the whole time instead (typing/deleting mid-recording works normally) and fills with the transcribed text live, in place; the mic button gets a Google Assistant-style listening cue instead — its circle fills with the theme's primary color (icon turns white), with a few rings pulsing outward from behind it on a loop. Tap it to stop (keeps the text); the send button (and Enter) still submits immediately while listening by stopping first. There's no cancel button in this Android UI — `cancelRecording()` remains available programmatically via a template ref.
|
|
10
|
+
- **Fixed**: `AbChatInput` voice input on Android — text was only appearing once the user tapped stop, and could double up when it did (words repeating mid-recording, not just at the end). Android's `continuous`+`interimResults` combination turned out unreliable across builds in a way delta-tracking `e.results` (by `resultIndex` or by position) can't fully work around — it can restate/duplicate earlier words in a later result with no restart involved at all. Android now runs one utterance per internal recognition session (`continuous: false`) instead, relying on the existing transparent onend-restart (added earlier for a Safari quirk) to pick the next utterance back up automatically — so `onresult` only ever needs that session's latest result, with no cross-event bookkeeping to get wrong. Combined with the textarea staying editable during recording (see above), `onresult` now also reads the current text and swaps out only the exact suffix it last inserted, so a manual edit mid-recording is preserved instead of being silently overwritten.
|
|
11
|
+
- **Fixed**: `AbChatInput`'s Android listening cue (see above) — the solid circle and ring animation never actually rendered, in either light or dark mode. They referenced `--#{$prefix}apbd-primary`, a CSS variable that isn't defined anywhere in the project; with no fallback, `var()` resolves to nothing and the whole declaration is silently dropped. Now uses `--#{$prefix}theme` (the actual theme accent variable, defined per-skin for both modes), with a `#0d6efd` fallback for safety.
|
|
12
|
+
- **Changed**: `AbChatInput`'s Android listening rings scaled down slightly (max `2.4` → `1.7`) — the previous size read as too large next to the language badge and send button. The textarea also refocuses automatically now the moment listening ends, on every platform (stop, cancel, or a voice-triggered submit) — the cursor lands back in it immediately instead of requiring an extra tap.
|
|
13
|
+
- **Fixed**: `AbChatInput`'s mic button on touchscreens — its `:hover` background had no touch guard, so tapping it (e.g. to stop recording on Android) could leave a lingering gray circle behind, a well-known mobile quirk: touch has no real pointer to move away and clear `:hover` the way a mouse does. Wrapped in `@media (hover: hover)` so it only applies on devices with genuine hover capability.
|
|
14
|
+
- **Added**: `AbChatInput` `voicePunctuationCommands` and `voiceAutoPunctuate` props (both `Boolean`, default `true`, independently toggleable) for voice input punctuation. `voicePunctuationCommands`: saying a punctuation word inserts the actual mark — English `"period"`/`"full stop"` → `.`, `"comma"` → `,`, `"question mark"` → `?`; Bengali `"পূর্ণচ্ছেদ"` → `।`, `"কমা"` → `,`, `"প্রশ্নবোধক"` → `?` — matched against the transcript text itself, independent of the selected recognition language. `voiceAutoPunctuate`: a sentence-ending mark (`.`, or `।` when `voiceLang` starts with `bn`) is inserted between voice utterances (each final phrase on non-Android, each per-utterance restart on Android) whenever the existing text doesn't already end with one.
|
|
15
|
+
- **Fixed**: `AbChatInput`'s `voicePunctuationCommands` (see above) — command-word matching used `\b`, which only recognizes ASCII letters/digits as "word" characters and is effectively a no-op for Bengali script, so a Bengali trigger word could match as a substring inside an unrelated longer word (e.g. saying "দাঁড়িপাল্লা" — "scale/balance" — got mangled into "। পাল্লা"). Now uses script-agnostic lookaround instead, matching only when the word is actually standalone. `"দাড়ি"` was also dropped entirely as a trigger (not just boundary-guarded) — fixing the substring match doesn't fix it also being ordinary vocabulary (beard), so a sentence genuinely about a beard would still lose that word every time; `"পূর্ণচ্ছেদ"` (a purely technical term nobody says in normal conversation) remains as the sole Bengali trigger for `.`/`।`.
|
|
16
|
+
- **Added**: `AbVoiceButton` — a standalone voice-to-text mic button, the same recognition engine as `AbChatInput`'s built-in mic with no composer attached. `v-model` for the transcribed text; `voice-start`/`voice-stop`/`voice-cancel`/`voice-error` events; `startRecording()`/`stopRecording()`/`cancelRecording()` exposed methods. `size` (px, default `40`) and `lang` (BCP-47, auto-detected when unset — no built-in language picker here) props, plus the same `voicePunctuationCommands`/`voiceAutoPunctuate` props as `AbChatInput`. Unlike `AbChatInput`, the Google Assistant-style listening cue (solid theme-color circle + pulsing rings) and the live, per-utterance recognition architecture run on every platform here, not just Android — this component has no legacy full recording-bar behavior to preserve, so there was no reason to keep the two paths.
|
|
17
|
+
- **Changed**: `AbChatInput` voice recording — the Google Assistant-style listening cue (mic icon stays put with pulsing rings, textarea stays visible and live-editable the whole time) now runs on every platform, not just Android, matching `AbVoiceButton`'s architecture. The separate full-width recording bar (audio-reactive waveform + cancel/stop/submit buttons), previously kept for every platform except Android, is removed entirely — there's no dedicated cancel button in the UI anymore; `cancelRecording()` remains available programmatically via a template ref, and the default send button (or `submit()`/Enter) still stops-then-submits when used while listening.
|
|
18
|
+
- **Fixed**: `AbChatInput` voice-to-text not reliably converting speech on non-Android platforms — the old pipeline only ever committed text off a `SpeechRecognition` result's `isFinal` flag, which some browsers/builds hold back indefinitely instead of firing per pause segment, so speech could go untranscribed until — or even past — the point the user stopped recording. Every platform now runs the same per-utterance (`continuous: false`) + `interimResults: true` architecture already proven on Android, merging every recognized chunk into the text live instead of waiting on `isFinal`; the now-unused `getUserMedia`/`AnalyserNode` waveform pipeline (mic-hardware-exclusive, and irrelevant once the waveform UI it drove is gone) was removed along with it.
|
|
19
|
+
- **Fixed**: `AbChatInput` and `AbVoiceButton` mic button showing "Microphone permission denied" on Safari (desktop and iOS) after the `interimResults: true` change above — Safari's `SpeechRecognition` engine has a long-standing bug where turning on `interimResults` can fail to (re)start at all, surfacing as a generic `onerror('not-allowed')` indistinguishable from an actually-denied permission. Safari now keeps `interimResults: false` (final-only, its reliably-supported mode) while every other browser still gets live interim updates; `onresult`'s merge logic already handled final-only results correctly, so no other change was needed.
|
|
20
|
+
- **Fixed**: `AbChatInput` voice input transcribing sentences entirely lowercase (e.g. "hello how are you. hello" instead of "Hello how are you. Hello") — recognized speech was inserted as-is with no capitalization pass. Both existing punctuation props now also auto-capitalize the sentence they start: `voiceAutoPunctuate` capitalizes the first letter of a new utterance right after inserting a boundary mark (and the very first letter of the whole message unconditionally); `voicePunctuationCommands` capitalizes the letter right after any mark it inserts mid-utterance (`"hello period how are you"` → `"Hello. How are you"`). Applied only to the freshly recognized chunk, never to already-committed text, so it can't fight a manual edit made to an earlier sentence while still recording. Uses plain `toUpperCase()` on the matched letter — a safe no-op for scripts without letter case (Bengali, Arabic, CJK, …), so it needs no per-language list to work for any cased script.
|
|
21
|
+
|
|
5
22
|
## [1.0.15] - 2026-08-24
|
|
6
23
|
|
|
7
24
|
- **Added**: `AbChatBox` — a full chat conversation container built on top of `AbChatInput`: header (title/subtitle/avatar, or fully custom via the `header`/`header-actions` slots), a scrollable message list with a default bubble renderer (overridable per-message via `message`/`message-avatar`), empty and typing states (`empty`/`typing` slots), and the composer docked at the bottom. `v-model:messages` holds the conversation, `v-model` holds the composer text; submitting auto-appends the user's message and fires `send`. Every `AbChatInput` prop, event, and slot (`left`/`right`/`send-button`/`menu-trigger`/`single-input`/`multiple-input`) is forwarded straight through to the inner composer.
|