@hachej/boring-ui-kit 0.4.46 → 0.4.48
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 +0 -4
- package/dist/chat-react-session.d.ts +1 -0
- package/dist/chat-react-session.js +12 -3
- package/dist/chat-view.d.ts +2 -1
- package/dist/native-chat.d.ts +39 -2
- package/dist/native-chat.js +135 -9
- package/dist/remote-chat.d.ts +6 -0
- package/dist/remote-chat.js +22 -0
- package/dist/shared-chat/index.d.ts +1 -1
- package/package.json +2 -6
- package/r/agent-target.json +4 -4
- package/r/app-shell.json +12 -12
- package/r/board-viewer.json +6 -6
- package/r/button.json +1 -1
- package/r/dock.json +1 -1
- package/r/documents.json +12 -12
- package/r/feedback.json +24 -12
- package/r/file-tree.json +4 -4
- package/r/highlights.json +3 -3
- package/r/html-viewer.json +3 -3
- package/r/looks-viewer.json +2 -2
- package/r/maquette-viewer.json +1 -1
- package/r/markdown-editor.json +3 -3
- package/r/mockup-viewer.json +1 -1
- package/r/pi-ambient.json +9 -9
- package/r/pi-app-kinds.json +10 -10
- package/r/pi-app.json +12 -12
- package/r/pi-artifacts.json +2 -2
- package/r/pi-chat-approval.json +2 -2
- package/r/pi-chat-attachments.json +1 -1
- package/r/pi-chat-markdown.json +2 -2
- package/r/pi-chat-mentions.json +1 -1
- package/r/pi-chat-pickers.json +1 -1
- package/r/pi-chat-plugins.json +11 -11
- package/r/pi-chat-question.json +1 -1
- package/r/pi-chat-slash.json +2 -2
- package/r/pi-chat-subagent.json +1 -1
- package/r/pi-chat-voice.json +9 -3
- package/r/pi-chat.json +11 -24
- package/r/pi-workspace.json +3 -3
- package/r/placed-agent.json +4 -4
- package/r/provider-setup.json +1 -1
- package/r/registry.json +1211 -1381
- package/r/shared-chat.json +6 -6
- package/r/spaces.json +44 -0
- package/r/task-list-viewer.json +2 -2
- package/r/version-history.json +2 -2
- package/r/viewer-code.json +2 -2
- package/r/viewer-frame.json +4 -4
- package/r/viewer-html.json +4 -4
- package/r/viewer-image.json +2 -2
- package/r/viewer-markdown.json +5 -5
- package/r/viewer-pdf.json +3 -3
- package/r/viewers.json +6 -6
- package/r/windows.json +1 -1
- package/dist/task-board.d.ts +0 -96
- package/dist/task-board.js +0 -48
- package/r/feedback-preview.json +0 -20
- package/r/pm-panel.json +0 -122
- package/r/requests-board.json +0 -33
- package/r/task-board.json +0 -41
- package/r/task-mentions.json +0 -25
package/r/pi-chat-voice.json
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
"title": "Pi chat voice messages",
|
|
5
5
|
"description": "Tap-to-record voice messages: a compatibility export of the kit's chat-react/voice recorder hook, the composer's record button and the pending voice bubble, plus useHoldToRecord. Plug it in with `voiceMessage={{ ...config, ...voiceMessagePlugin }}`; without it pi-chat has no voice button.",
|
|
6
6
|
"dependencies": [
|
|
7
|
-
"@hachej/boring-ui-kit@^0.4.
|
|
7
|
+
"@hachej/boring-ui-kit@^0.4.48",
|
|
8
8
|
"react@^19.0.0",
|
|
9
9
|
"lucide-react@^1.51.0"
|
|
10
10
|
],
|
|
11
11
|
"registryDependencies": [
|
|
12
|
-
"https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.4.
|
|
13
|
-
"https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.4.
|
|
12
|
+
"https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.4.48/r/utils.json",
|
|
13
|
+
"https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.4.48/r/pi-chat.json"
|
|
14
14
|
],
|
|
15
15
|
"files": [
|
|
16
16
|
{
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
"content": "'use client';\n\nimport { CircleIcon, MicIcon, PauseIcon, PlayIcon, Trash2Icon } from 'lucide-react';\nimport { Button } from '@/components/ui/button';\nimport { Spinner } from '@/components/ui/spinner';\nimport { Bubble, BubbleContent } from '@/components/ui/bubble';\nimport { Message, MessageContent } from '@/components/ui/message';\nimport { useChatText } from '../pi-chat/labels';\nimport { voiceClock } from '../pi-chat/config';\nimport type { PendingVoiceBubbleProps, VoiceMessageButtonProps } from '../pi-chat/config';\nimport { useVoiceMessage } from './use-voice-message';\n\nexport { voiceClock } from '../pi-chat/config';\n\n/** The same recording row for native chat and a shell-owned capture. It replaces the editable composer controls. */\nexport function RecordingBar({ voice, testId = 'voice-message-record' }: Pick<VoiceMessageButtonProps, 'voice' | 'testId'>) {\n const { labels, icons } = useChatText();\n return <div data-testid=\"voice-recording-bar\" data-state={voice.paused ? 'paused' : voice.phase} className=\"flex w-full min-w-0 items-center gap-2\">\n <Button variant=\"ghost\" size=\"icon\" data-testid=\"composer-voice-cancel\" aria-label={labels.voiceCancel} title={labels.voiceCancel} onClick={voice.cancel} className=\"min-h-11 min-w-11 shrink-0\"><Trash2Icon aria-hidden=\"true\" /></Button>\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <CircleIcon className=\"size-3 shrink-0 fill-current text-destructive\" aria-hidden=\"true\" />\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-testid=\"voice-recording\" className=\"shrink-0 tabular-nums\"><span className=\"sr-only\">{voice.paused ? labels.voicePaused : labels.voiceRecording} </span>{voiceClock(voice.seconds)}</span>\n {!!voice.levels?.length && <div data-testid=\"voice-waveform\" aria-hidden=\"true\" className=\"flex h-8 min-w-0 flex-1 items-center justify-end gap-0.5 overflow-hidden\">\n {voice.levels.map((level, index) => <span key={index} data-level={level} className=\"w-1 shrink-0 bg-muted-foreground\" style={{ height: `${Math.max(5, Math.sqrt(Math.min(1, level)) * 100)}%` }} />)}\n </div>}\n </div>\n {voice.pause && voice.resume && <Button variant=\"ghost\" size=\"icon\" data-testid=\"voice-pause\" aria-label={voice.paused ? labels.voiceResumeRecording : labels.voicePauseRecording} title={voice.paused ? labels.voiceResumeRecording : labels.voicePauseRecording} onClick={voice.paused ? voice.resume : voice.pause} className=\"min-h-11 min-w-11 shrink-0\">{voice.paused ? <PlayIcon aria-hidden=\"true\" /> : <PauseIcon aria-hidden=\"true\" />}</Button>}\n <Button variant=\"default\" size=\"icon\" data-testid={testId} data-state={voice.phase} aria-label={labels.send} title={labels.send} onClick={voice.finish} disabled={voice.phase === 'starting'} className=\"min-h-11 min-w-11 shrink-0\"><icons.send aria-hidden=\"true\" /></Button>\n </div>;\n}\n\nexport function VoiceMessageButton({ voice, disabled, primary = false, testId = 'voice-message-record' }: VoiceMessageButtonProps) {\n const { labels } = useChatText();\n if (voice.phase === 'starting' || voice.phase === 'recording') return <RecordingBar voice={voice} testId={testId} />;\n return <Button onClick={voice.start} variant={primary ? 'default' : 'ghost'} size=\"icon\" className=\"min-h-11 min-w-11 shrink-0\" data-testid={testId} data-state={voice.phase} disabled={disabled || !voice.canStart || voice.phase !== 'idle'} aria-label={labels.voiceRecord} title={labels.voiceRecord}><MicIcon aria-hidden=\"true\" /></Button>;\n}\n\nexport function PendingVoiceBubble({ pending }: PendingVoiceBubbleProps) {\n const { labels } = useChatText();\n if (!pending) return null;\n const failed = pending.phase === 'transcribe-failed' || pending.phase === 'upload-failed';\n const blocked = pending.phase === 'blocked' || pending.phase === 'unconfirmed';\n return <Message align=\"end\" data-testid=\"voice-pending\" data-voice-id={pending.id} data-state={pending.phase}><MessageContent><Bubble variant=\"muted\" align=\"end\" className={failed || blocked ? 'w-full max-w-full' : undefined}><BubbleContent>\n <div role={failed ? 'alert' : 'status'} className=\"flex items-center gap-2\">\n {!failed && !blocked && <Spinner aria-hidden=\"true\" />}\n {Number.isFinite(pending.seconds) && pending.seconds > 0 && <span data-testid=\"voice-pending-duration\">{voiceClock(pending.seconds)}</span>}\n <span>{pending.phase === 'upload-failed' ? labels.uploadFailedShort : pending.phase === 'transcribe-failed' ? labels.voiceTranscribeFailed : pending.phase === 'blocked' ? labels.voiceBlocked : pending.phase === 'unconfirmed' ? labels.voiceUnconfirmed : labels.voicePreparing}</span>\n </div>\n {(failed || blocked) && <div className=\"mt-2 grid grid-cols-[auto_minmax(0,1fr)_auto] gap-2\">\n {failed && <Button size=\"sm\" className=\"h-auto min-h-11 min-w-0 whitespace-normal\" variant=\"outline\" data-testid=\"voice-retry\" onClick={pending.retry}>{labels.retry}</Button>}\n {pending.audioOnly && <Button size=\"sm\" className=\"h-auto min-h-11 min-w-0 whitespace-normal\" variant=\"outline\" data-testid=\"voice-audio-only\" onClick={pending.audioOnly}>{labels.voiceAudioOnly}</Button>}\n {pending.phase !== 'unconfirmed' && <Button size=\"sm\" className=\"h-auto min-h-11 min-w-0 whitespace-normal\" variant=\"ghost\" data-testid=\"voice-discard\" onClick={pending.discard}>{labels.voiceDiscard}</Button>}\n </div>}\n </BubbleContent></Bubble></MessageContent></Message>;\n}\n\n/** Tap-to-record voice messages for the chat: `voiceMessage={{ ...config, ...voiceMessagePlugin }}`. */\nexport const voiceMessagePlugin = { useRecorder: useVoiceMessage, Button: VoiceMessageButton, Bubble: PendingVoiceBubble } as const;\n",
|
|
31
31
|
"type": "registry:component",
|
|
32
32
|
"target": "components/pi-chat-voice/voice-message.tsx"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"path": "registry/pi-chat-voice/voice-input.tsx",
|
|
36
|
+
"content": "// A microphone button for the composer: records on the first click, stops on the second, transcribes the recording and appends the\n// text to the composer draft. It never sends: the person reads the transcript and presses Send. Pass it to `PiChat` as `tools`.\nimport { useDictation } from '@hachej/boring-ui-kit/chat-react/voice';\nimport { Loader2Icon, MicIcon, SquareIcon, XIcon } from 'lucide-react';\nimport type { NativeChatController } from '@hachej/boring-ui-kit/native-chat';\nimport { appendToDraft } from '@hachej/boring-ui-kit/chat-text';\nimport { useChatText } from '../pi-chat/labels';\nimport { Button } from '@/components/ui/button';\nimport { Toggle } from '@/components/ui/toggle';\n\nexport interface VoiceInputProps {\n /** The chat whose composer draft receives the transcript. */\n readonly controller: NativeChatController;\n /** Turns the recording into text. `signal` aborts when the person cancels or leaves the page; a rejection shows an error. */\n readonly transcribe: (audio: Blob, signal: AbortSignal) => Promise<string>;\n /** Capture limit (default five minutes); the person still finishes before text is appended. */\n readonly maxMs?: number | undefined;\n}\n\nexport function VoiceInput({ controller, transcribe, maxMs }: VoiceInputProps) {\n const { labels } = useChatText();\n const { phase, problem, start, finish, cancel } = useDictation({ transcribe, labels, maxMs, target: controller,\n onText: (spoken, signal) => {\n if (!signal.aborted) controller.setText(appendToDraft(controller.getSnapshot().draft.text, spoken));\n },\n });\n const onClick = () => { if (phase === 'idle') start(); else finish(); };\n const recording = phase === 'recording';\n const busy = phase === 'transcribing';\n return (\n <div className=\"flex items-center gap-1.5\">\n {(phase === 'starting' || recording || busy) && <Button variant=\"ghost\" size=\"icon\" data-testid=\"composer-voice-cancel\" aria-label={labels.voiceCancel} title={labels.voiceCancel} onClick={cancel}>\n <XIcon data-icon=\"inline-start\" aria-hidden=\"true\" /></Button>}\n <Toggle data-testid=\"composer-voice\" data-state={phase} pressed={recording} aria-label={phase === 'starting' ? labels.voiceCancel : recording ? labels.voiceStop : labels.voiceRecord}\n title={phase === 'starting' ? labels.voiceCancel : recording ? labels.voiceStop : labels.voiceRecord} disabled={busy} onPressedChange={onClick}>\n {busy ? <Loader2Icon data-icon=\"inline-start\" className=\"animate-spin motion-reduce:animate-none\" role=\"status\" aria-label={labels.voiceTranscribing} />\n : recording ? <SquareIcon data-icon=\"inline-start\" aria-hidden=\"true\" />\n : <MicIcon data-icon=\"inline-start\" aria-hidden=\"true\" />}\n </Toggle>\n {problem && <span role=\"alert\" data-testid=\"composer-voice-problem\" className=\"max-w-56 text-xs leading-4 text-destructive\">{problem}</span>}\n </div>\n );\n}\n",
|
|
37
|
+
"type": "registry:component",
|
|
38
|
+
"target": "components/pi-chat-voice/voice-input.tsx"
|
|
33
39
|
}
|
|
34
40
|
],
|
|
35
41
|
"type": "registry:block"
|