@revikornmann/muka-ui 0.16.0 → 0.17.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/dist/cjs/components/ChatComposer/ChatComposer.js +12 -4
- package/dist/cjs/components/ChatComposer/ChatComposer.js.map +1 -1
- package/dist/cjs/components/EmojiPicker/EmojiPicker.css +19 -0
- package/dist/cjs/components/EmojiPicker/EmojiPicker.js +54 -0
- package/dist/cjs/components/EmojiPicker/EmojiPicker.js.map +1 -0
- package/dist/cjs/components/EmojiPicker/index.js +12 -0
- package/dist/cjs/components/EmojiPicker/index.js.map +1 -0
- package/dist/cjs/components/PhotoDraftStrip/PhotoDraftStrip.css +27 -0
- package/dist/cjs/components/PhotoDraftStrip/PhotoDraftStrip.js +36 -0
- package/dist/cjs/components/PhotoDraftStrip/PhotoDraftStrip.js.map +1 -0
- package/dist/cjs/components/PhotoDraftStrip/index.js +11 -0
- package/dist/cjs/components/PhotoDraftStrip/index.js.map +1 -0
- package/dist/cjs/components/RecordingBar/RecordingBar.css +47 -0
- package/dist/cjs/components/RecordingBar/RecordingBar.js +22 -0
- package/dist/cjs/components/RecordingBar/RecordingBar.js.map +1 -0
- package/dist/cjs/components/RecordingBar/index.js +11 -0
- package/dist/cjs/components/RecordingBar/index.js.map +1 -0
- package/dist/cjs/components/VoiceMessage/VoiceMessage.css +29 -0
- package/dist/cjs/components/VoiceMessage/VoiceMessage.js +85 -0
- package/dist/cjs/components/VoiceMessage/VoiceMessage.js.map +1 -0
- package/dist/cjs/components/VoiceMessage/index.js +11 -0
- package/dist/cjs/components/VoiceMessage/index.js.map +1 -0
- package/dist/cjs/components/VoiceRecorder/audio.js +61 -0
- package/dist/cjs/components/VoiceRecorder/audio.js.map +1 -0
- package/dist/cjs/components/VoiceRecorder/index.js +16 -0
- package/dist/cjs/components/VoiceRecorder/index.js.map +1 -0
- package/dist/cjs/components/VoiceRecorder/useVoiceRecorder.js +213 -0
- package/dist/cjs/components/VoiceRecorder/useVoiceRecorder.js.map +1 -0
- package/dist/cjs/components/Waveform/Waveform.css +23 -0
- package/dist/cjs/components/Waveform/Waveform.js +36 -0
- package/dist/cjs/components/Waveform/Waveform.js.map +1 -0
- package/dist/cjs/components/Waveform/index.js +11 -0
- package/dist/cjs/components/Waveform/index.js.map +1 -0
- package/dist/cjs/components/index.js +18 -1
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/esm/components/ChatComposer/ChatComposer.js +12 -4
- package/dist/esm/components/ChatComposer/ChatComposer.js.map +1 -1
- package/dist/esm/components/EmojiPicker/EmojiPicker.css +19 -0
- package/dist/esm/components/EmojiPicker/EmojiPicker.js +50 -0
- package/dist/esm/components/EmojiPicker/EmojiPicker.js.map +1 -0
- package/dist/esm/components/EmojiPicker/index.js +3 -0
- package/dist/esm/components/EmojiPicker/index.js.map +1 -0
- package/dist/esm/components/PhotoDraftStrip/PhotoDraftStrip.css +27 -0
- package/dist/esm/components/PhotoDraftStrip/PhotoDraftStrip.js +32 -0
- package/dist/esm/components/PhotoDraftStrip/PhotoDraftStrip.js.map +1 -0
- package/dist/esm/components/PhotoDraftStrip/index.js +3 -0
- package/dist/esm/components/PhotoDraftStrip/index.js.map +1 -0
- package/dist/esm/components/RecordingBar/RecordingBar.css +47 -0
- package/dist/esm/components/RecordingBar/RecordingBar.js +18 -0
- package/dist/esm/components/RecordingBar/RecordingBar.js.map +1 -0
- package/dist/esm/components/RecordingBar/index.js +3 -0
- package/dist/esm/components/RecordingBar/index.js.map +1 -0
- package/dist/esm/components/VoiceMessage/VoiceMessage.css +29 -0
- package/dist/esm/components/VoiceMessage/VoiceMessage.js +81 -0
- package/dist/esm/components/VoiceMessage/VoiceMessage.js.map +1 -0
- package/dist/esm/components/VoiceMessage/index.js +3 -0
- package/dist/esm/components/VoiceMessage/index.js.map +1 -0
- package/dist/esm/components/VoiceRecorder/audio.js +55 -0
- package/dist/esm/components/VoiceRecorder/audio.js.map +1 -0
- package/dist/esm/components/VoiceRecorder/index.js +4 -0
- package/dist/esm/components/VoiceRecorder/index.js.map +1 -0
- package/dist/esm/components/VoiceRecorder/useVoiceRecorder.js +210 -0
- package/dist/esm/components/VoiceRecorder/useVoiceRecorder.js.map +1 -0
- package/dist/esm/components/Waveform/Waveform.css +23 -0
- package/dist/esm/components/Waveform/Waveform.js +32 -0
- package/dist/esm/components/Waveform/Waveform.js.map +1 -0
- package/dist/esm/components/Waveform/index.js +3 -0
- package/dist/esm/components/Waveform/index.js.map +1 -0
- package/dist/esm/components/index.js +6 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/styles/components/EmojiPicker.css +19 -0
- package/dist/styles/components/PhotoDraftStrip.css +27 -0
- package/dist/styles/components/RecordingBar.css +47 -0
- package/dist/styles/components/VoiceMessage.css +29 -0
- package/dist/styles/components/Waveform.css +23 -0
- package/dist/styles/index.css +516 -356
- package/dist/styles/muka-dark.css +516 -356
- package/dist/styles/muka-light.css +516 -356
- package/dist/styles/wireframe-dark.css +516 -356
- package/dist/styles/wireframe-light.css +516 -356
- package/dist/types/components/ChatComposer/ChatComposer.d.ts +7 -0
- package/dist/types/components/ChatComposer/ChatComposer.d.ts.map +1 -1
- package/dist/types/components/EmojiPicker/EmojiPicker.d.ts +28 -0
- package/dist/types/components/EmojiPicker/EmojiPicker.d.ts.map +1 -0
- package/dist/types/components/EmojiPicker/index.d.ts +3 -0
- package/dist/types/components/EmojiPicker/index.d.ts.map +1 -0
- package/dist/types/components/PhotoDraftStrip/PhotoDraftStrip.d.ts +51 -0
- package/dist/types/components/PhotoDraftStrip/PhotoDraftStrip.d.ts.map +1 -0
- package/dist/types/components/PhotoDraftStrip/index.d.ts +3 -0
- package/dist/types/components/PhotoDraftStrip/index.d.ts.map +1 -0
- package/dist/types/components/RecordingBar/RecordingBar.d.ts +22 -0
- package/dist/types/components/RecordingBar/RecordingBar.d.ts.map +1 -0
- package/dist/types/components/RecordingBar/index.d.ts +3 -0
- package/dist/types/components/RecordingBar/index.d.ts.map +1 -0
- package/dist/types/components/VoiceMessage/VoiceMessage.d.ts +34 -0
- package/dist/types/components/VoiceMessage/VoiceMessage.d.ts.map +1 -0
- package/dist/types/components/VoiceMessage/index.d.ts +3 -0
- package/dist/types/components/VoiceMessage/index.d.ts.map +1 -0
- package/dist/types/components/VoiceRecorder/audio.d.ts +20 -0
- package/dist/types/components/VoiceRecorder/audio.d.ts.map +1 -0
- package/dist/types/components/VoiceRecorder/index.d.ts +4 -0
- package/dist/types/components/VoiceRecorder/index.d.ts.map +1 -0
- package/dist/types/components/VoiceRecorder/useVoiceRecorder.d.ts +48 -0
- package/dist/types/components/VoiceRecorder/useVoiceRecorder.d.ts.map +1 -0
- package/dist/types/components/Waveform/Waveform.d.ts +31 -0
- package/dist/types/components/Waveform/Waveform.d.ts.map +1 -0
- package/dist/types/components/Waveform/index.d.ts +3 -0
- package/dist/types/components/Waveform/index.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +6 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -17,7 +17,7 @@ require("./ChatComposer.css");
|
|
|
17
17
|
* strip. Submits on Enter (Shift+Enter for a newline). Designed to live in a
|
|
18
18
|
* `BottomBar`.
|
|
19
19
|
*/
|
|
20
|
-
exports.ChatComposer = (0, react_1.forwardRef)(({ value, onChange, onSubmit, placeholder = 'Reply...', onLeadingClick, leadingIcon = 'add', leadingLabel = 'Add attachment', onEmoji, showEmoji = true, emojiLabel = 'Add emoji', onRecordStart, micLabel = 'Record voice message', sendLabel = 'Send message', recording = false, recordingSlot, onRecordPause, onRecordDiscard, pauseLabel = 'Pause recording', discardLabel = 'Discard recording', attachments, attachmentsOverflowLabel = 'Show more attachments', loading = false, disabled = false, maxLines = 10, autoFocus = false, className = '', }, forwardedRef) => {
|
|
20
|
+
exports.ChatComposer = (0, react_1.forwardRef)(({ value, onChange, onSubmit, placeholder = 'Reply...', onLeadingClick, leadingIcon = 'add', leadingLabel = 'Add attachment', onEmoji, showEmoji = true, emojiLabel = 'Add emoji', onRecordStart, micLabel = 'Record voice message', sendLabel = 'Send message', canSubmit: canSubmitProp, recording = false, recordingSlot, onRecordPause, onRecordDiscard, pauseLabel = 'Pause recording', discardLabel = 'Discard recording', attachments, attachmentsOverflowLabel = 'Show more attachments', loading = false, disabled = false, maxLines = 10, autoFocus = false, className = '', }, forwardedRef) => {
|
|
21
21
|
const textareaRef = (0, react_1.useRef)(null);
|
|
22
22
|
const attachmentsRef = (0, react_1.useRef)(null);
|
|
23
23
|
(0, react_1.useImperativeHandle)(forwardedRef, () => textareaRef.current);
|
|
@@ -33,9 +33,12 @@ exports.ChatComposer = (0, react_1.forwardRef)(({ value, onChange, onSubmit, pla
|
|
|
33
33
|
el.style.height = `${next}px`;
|
|
34
34
|
el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden';
|
|
35
35
|
}, [value, maxLines, recording]);
|
|
36
|
+
// `canSubmit` overrides the default "text is non-empty" rule when provided,
|
|
37
|
+
// so a caption-less gallery send can be enabled from staged attachments.
|
|
38
|
+
const textEnabled = canSubmitProp ?? value.trim().length > 0;
|
|
36
39
|
const canSubmit = recording
|
|
37
40
|
? !disabled && !loading
|
|
38
|
-
: !disabled && !loading &&
|
|
41
|
+
: !disabled && !loading && textEnabled;
|
|
39
42
|
const handleSubmit = () => {
|
|
40
43
|
if (!canSubmit)
|
|
41
44
|
return;
|
|
@@ -54,8 +57,13 @@ exports.ChatComposer = (0, react_1.forwardRef)(({ value, onChange, onSubmit, pla
|
|
|
54
57
|
el.scrollBy({ left: el.clientWidth * 0.8, behavior: 'smooth' });
|
|
55
58
|
};
|
|
56
59
|
// Trailing button is a mic only when the field is empty, not recording, and
|
|
57
|
-
// a record handler is supplied; otherwise it is the send button.
|
|
58
|
-
|
|
60
|
+
// a record handler is supplied; otherwise it is the send button. When send
|
|
61
|
+
// enablement is controlled (`canSubmit`), always show send so a caption-less
|
|
62
|
+
// gallery can be sent from an empty field.
|
|
63
|
+
const showMic = !recording &&
|
|
64
|
+
onRecordStart &&
|
|
65
|
+
canSubmitProp === undefined &&
|
|
66
|
+
value.trim().length === 0;
|
|
59
67
|
const classes = [
|
|
60
68
|
'muka-chat-composer',
|
|
61
69
|
recording && 'muka-chat-composer--recording',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatComposer.js","sourceRoot":"","sources":["../../../../components/ChatComposer/ChatComposer.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;AAEb,iCAKe;AACf,sCAAmC;AACnC,kCAA8C;AAC9C,wCAAqC;AACrC,8BAA4B;
|
|
1
|
+
{"version":3,"file":"ChatComposer.js","sourceRoot":"","sources":["../../../../components/ChatComposer/ChatComposer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* EmojiPicker Component Styles */
|
|
2
|
+
|
|
3
|
+
.muka-emoji-picker {
|
|
4
|
+
display: grid;
|
|
5
|
+
grid-template-columns: repeat(8, 1fr);
|
|
6
|
+
gap: var(--spacing-1);
|
|
7
|
+
padding: var(--spacing-2);
|
|
8
|
+
max-height: 12rem;
|
|
9
|
+
overflow-y: auto;
|
|
10
|
+
background: var(--color-surface-level2);
|
|
11
|
+
border: var(--border-width-regular, 1px) solid var(--color-border-default);
|
|
12
|
+
border-radius: var(--radius-lg);
|
|
13
|
+
box-shadow: var(--menu-content-shadow, 0 4px 12px rgba(0, 0, 0, 0.12));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.muka-emoji-picker__glyph {
|
|
17
|
+
font-size: 1.25rem;
|
|
18
|
+
line-height: 1;
|
|
19
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.EmojiPicker = exports.DEFAULT_EMOJI = void 0;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const Button_1 = require("../Button");
|
|
8
|
+
require("./EmojiPicker.css");
|
|
9
|
+
/** A small default set of common Unicode emoji. Override via the `emoji` prop. */
|
|
10
|
+
exports.DEFAULT_EMOJI = [
|
|
11
|
+
'😀', '😄', '😉', '😊', '😍', '😘', '😎', '🤔',
|
|
12
|
+
'😅', '😂', '🙃', '😴', '😇', '🥳', '😢', '😡',
|
|
13
|
+
'👍', '👎', '👌', '🙏', '👏', '💪', '🤝', '✌️',
|
|
14
|
+
'👋', '🫡', '🔥', '✅', '❌', '⚠️', '❗', '❓',
|
|
15
|
+
'💯', '🎉', '⭐', '❤️', '💥', '👀', '💡', '⏰',
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* EmojiPicker — a minimal panel of Unicode emoji that inserts into a composer.
|
|
19
|
+
*
|
|
20
|
+
* Optional and dependency-free: apps may ignore it and wire only
|
|
21
|
+
* `ChatComposer.onEmoji`. Emoji are plain text, so once inserted they render in
|
|
22
|
+
* sent bubbles for free. Closes on Escape or an outside click.
|
|
23
|
+
*/
|
|
24
|
+
const EmojiPicker = ({ open, onClose, onSelect, title = 'Emoji', emoji = exports.DEFAULT_EMOJI, className = '', }) => {
|
|
25
|
+
const panelRef = (0, react_1.useRef)(null);
|
|
26
|
+
(0, react_1.useEffect)(() => {
|
|
27
|
+
if (!open)
|
|
28
|
+
return;
|
|
29
|
+
const onKey = (e) => {
|
|
30
|
+
if (e.key === 'Escape')
|
|
31
|
+
onClose();
|
|
32
|
+
};
|
|
33
|
+
const onPointer = (e) => {
|
|
34
|
+
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
35
|
+
onClose();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
document.addEventListener('keydown', onKey);
|
|
39
|
+
// Defer so the opening click doesn't immediately close the panel.
|
|
40
|
+
const id = window.setTimeout(() => document.addEventListener('pointerdown', onPointer), 0);
|
|
41
|
+
return () => {
|
|
42
|
+
document.removeEventListener('keydown', onKey);
|
|
43
|
+
window.clearTimeout(id);
|
|
44
|
+
document.removeEventListener('pointerdown', onPointer);
|
|
45
|
+
};
|
|
46
|
+
}, [open, onClose]);
|
|
47
|
+
if (!open)
|
|
48
|
+
return null;
|
|
49
|
+
const classes = ['muka-emoji-picker', className].filter(Boolean).join(' ');
|
|
50
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: panelRef, className: classes, role: "dialog", "aria-label": title, children: emoji.map((char) => ((0, jsx_runtime_1.jsx)(Button_1.Button, { variant: "ghost", size: "sm", iconOnly: true, "aria-label": char, onClick: () => onSelect(char), children: (0, jsx_runtime_1.jsx)("span", { className: "muka-emoji-picker__glyph", children: char }) }, char))) }));
|
|
51
|
+
};
|
|
52
|
+
exports.EmojiPicker = EmojiPicker;
|
|
53
|
+
exports.default = exports.EmojiPicker;
|
|
54
|
+
//# sourceMappingURL=EmojiPicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmojiPicker.js","sourceRoot":"","sources":["../../../../components/EmojiPicker/EmojiPicker.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = exports.DEFAULT_EMOJI = exports.EmojiPicker = void 0;
|
|
7
|
+
var EmojiPicker_1 = require("./EmojiPicker");
|
|
8
|
+
Object.defineProperty(exports, "EmojiPicker", { enumerable: true, get: function () { return EmojiPicker_1.EmojiPicker; } });
|
|
9
|
+
Object.defineProperty(exports, "DEFAULT_EMOJI", { enumerable: true, get: function () { return EmojiPicker_1.DEFAULT_EMOJI; } });
|
|
10
|
+
var EmojiPicker_2 = require("./EmojiPicker");
|
|
11
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(EmojiPicker_2).default; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../components/EmojiPicker/index.ts"],"names":[],"mappings":";;;;;;AAAA,6CAIuB;AAHrB,0GAAA,WAAW,OAAA;AAEX,4GAAA,aAAa,OAAA;AAEf,6CAAwC;AAA/B,uHAAA,OAAO,OAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* PhotoDraftStrip Component Styles */
|
|
2
|
+
|
|
3
|
+
.muka-photo-draft-strip {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: var(--spacing-3);
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding: var(--spacing-2) 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.muka-photo-draft-strip__track {
|
|
12
|
+
display: flex;
|
|
13
|
+
gap: var(--spacing-2);
|
|
14
|
+
flex: 1 1 auto;
|
|
15
|
+
min-width: 0;
|
|
16
|
+
overflow-x: auto;
|
|
17
|
+
scroll-behavior: smooth;
|
|
18
|
+
scrollbar-width: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.muka-photo-draft-strip__track::-webkit-scrollbar {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.muka-photo-draft-strip__item {
|
|
26
|
+
flex: 0 0 auto;
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.PhotoDraftStrip = void 0;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const Button_1 = require("../Button");
|
|
7
|
+
const Icon_1 = require("../Icon");
|
|
8
|
+
const Spinner_1 = require("../Spinner");
|
|
9
|
+
const Thumbnail_1 = require("../Thumbnail");
|
|
10
|
+
require("./PhotoDraftStrip.css");
|
|
11
|
+
/**
|
|
12
|
+
* PhotoDraftStrip — a controlled, horizontally-scrolling strip of staged photos
|
|
13
|
+
* shown above the composer while they upload. Each tile is a Muka `Thumbnail`
|
|
14
|
+
* carrying its own upload progress / error and a remove (×) control, so a
|
|
15
|
+
* per-item failure never blocks sending the rest.
|
|
16
|
+
*
|
|
17
|
+
* Controlled and network-free: the app owns upload, object URLs and the cap on
|
|
18
|
+
* how many photos may be staged. The optional send button lives here because
|
|
19
|
+
* the composer only enables its own send once text is non-empty — it can't send
|
|
20
|
+
* a caption-less gallery. Sending is enabled once every tile has settled and at
|
|
21
|
+
* least one uploaded successfully.
|
|
22
|
+
*/
|
|
23
|
+
const PhotoDraftStrip = ({ photos, onRemove, onSend, sending = false, showSend = true, sendLabel = 'Send photos', removeLabel = 'Remove photo', viewLabel = 'View photo', errorCaption = 'Upload failed', className = '', }) => {
|
|
24
|
+
if (photos.length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
// Allow sending once every tile settled (uploaded or failed) and at least one
|
|
27
|
+
// uploaded successfully — a failed tile shouldn't block the rest.
|
|
28
|
+
const anyUploading = photos.some((p) => p.status === 'uploading');
|
|
29
|
+
const anyReady = photos.some((p) => p.status === 'ready');
|
|
30
|
+
const canSend = !sending && !anyUploading && anyReady;
|
|
31
|
+
const classes = ['muka-photo-draft-strip', className].filter(Boolean).join(' ');
|
|
32
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: classes, children: [(0, jsx_runtime_1.jsx)("div", { className: "muka-photo-draft-strip__track", children: photos.map((photo) => ((0, jsx_runtime_1.jsx)("div", { className: "muka-photo-draft-strip__item", children: (0, jsx_runtime_1.jsx)(Thumbnail_1.Thumbnail, { src: photo.previewUrl, alt: photo.fileName, shape: "1:1", processing: photo.status === 'uploading' && photo.progress <= 0, loading: photo.status === 'uploading' && photo.progress > 0, progress: photo.progress, error: photo.status === 'error', caption: photo.status === 'error' ? errorCaption : undefined, onRemove: () => onRemove(photo.id), removeLabel: removeLabel, viewLabel: viewLabel }) }, photo.id))) }), showSend && ((0, jsx_runtime_1.jsx)(Button_1.Button, { variant: "primary", size: "lg", iconOnly: true, "aria-label": sendLabel, onClick: onSend, disabled: !canSend, children: sending ? ((0, jsx_runtime_1.jsx)(Spinner_1.Spinner, { size: "sm", variant: "inverse" })) : ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "send-plane2", size: "md" })) }))] }));
|
|
33
|
+
};
|
|
34
|
+
exports.PhotoDraftStrip = PhotoDraftStrip;
|
|
35
|
+
exports.default = exports.PhotoDraftStrip;
|
|
36
|
+
//# sourceMappingURL=PhotoDraftStrip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhotoDraftStrip.js","sourceRoot":"","sources":["../../../../components/PhotoDraftStrip/PhotoDraftStrip.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;AAGb,sCAAmC;AACnC,kCAA+B;AAC/B,wCAAqC;AACrC,4CAAyC;AACzC,iCAA+B;AA+C/B;;;;;;;;;;;GAWG;AACI,MAAM,eAAe,GAAmC,CAAC,EAC9D,MAAM,EACN,QAAQ,EACR,MAAM,EACN,OAAO,GAAG,KAAK,EACf,QAAQ,GAAG,IAAI,EACf,SAAS,GAAG,aAAa,EACzB,WAAW,GAAG,cAAc,EAC5B,SAAS,GAAG,YAAY,EACxB,YAAY,GAAG,eAAe,EAC9B,SAAS,GAAG,EAAE,GACf,EAAE,EAAE;IACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,8EAA8E;IAC9E,kEAAkE;IAClE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,YAAY,IAAI,QAAQ,CAAC;IAEtD,MAAM,OAAO,GAAG,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEhF,OAAO,CACL,iCAAK,SAAS,EAAE,OAAO,aACrB,gCAAK,SAAS,EAAC,+BAA+B,YAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,gCAAoB,SAAS,EAAC,8BAA8B,YAC1D,uBAAC,qBAAS,IACR,GAAG,EAAE,KAAK,CAAC,UAAU,EACrB,GAAG,EAAE,KAAK,CAAC,QAAQ,EACnB,KAAK,EAAC,KAAK,EACX,UAAU,EAAE,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,EAC/D,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,EAC3D,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,KAAK,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,EAC/B,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,EAC5D,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAClC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,GACpB,IAbM,KAAK,CAAC,EAAE,CAcZ,CACP,CAAC,GACE,EAEL,QAAQ,IAAI,CACX,uBAAC,eAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,QAAQ,sBACI,SAAS,EACrB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,OAAO,YAEjB,OAAO,CAAC,CAAC,CAAC,CACT,uBAAC,iBAAO,IAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,GAAG,CACxC,CAAC,CAAC,CAAC,CACF,uBAAC,WAAI,IAAC,IAAI,EAAC,aAAa,EAAC,IAAI,EAAC,IAAI,GAAG,CACtC,GACM,CACV,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AA9DW,QAAA,eAAe,mBA8D1B;AAEF,kBAAe,uBAAe,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = exports.PhotoDraftStrip = void 0;
|
|
7
|
+
var PhotoDraftStrip_1 = require("./PhotoDraftStrip");
|
|
8
|
+
Object.defineProperty(exports, "PhotoDraftStrip", { enumerable: true, get: function () { return PhotoDraftStrip_1.PhotoDraftStrip; } });
|
|
9
|
+
var PhotoDraftStrip_2 = require("./PhotoDraftStrip");
|
|
10
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(PhotoDraftStrip_2).default; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../components/PhotoDraftStrip/index.ts"],"names":[],"mappings":";;;;;;AAAA,qDAI2B;AAHzB,kHAAA,eAAe,OAAA;AAIjB,qDAA4C;AAAnC,2HAAA,OAAO,OAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* RecordingBar Component Styles */
|
|
2
|
+
|
|
3
|
+
.muka-recording-bar {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: var(--spacing-3);
|
|
7
|
+
width: 100%;
|
|
8
|
+
min-width: 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.muka-recording-bar__dot {
|
|
12
|
+
flex: 0 0 auto;
|
|
13
|
+
width: 0.625rem;
|
|
14
|
+
height: 0.625rem;
|
|
15
|
+
border-radius: var(--radius-full, 9999px);
|
|
16
|
+
background: var(--alert-color-error-accent, var(--color-text-default-default));
|
|
17
|
+
animation: muka-recording-bar-pulse 1s ease-in-out infinite;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.muka-recording-bar__time {
|
|
21
|
+
flex: 0 0 auto;
|
|
22
|
+
font-size: var(--text-label-sm-fontSize, 0.75rem);
|
|
23
|
+
line-height: var(--text-label-sm-lineHeight, 1);
|
|
24
|
+
font-variant-numeric: tabular-nums;
|
|
25
|
+
color: var(--color-text-default-default);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.muka-recording-bar__wave {
|
|
29
|
+
flex: 1 1 auto;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes muka-recording-bar-pulse {
|
|
34
|
+
0%,
|
|
35
|
+
100% {
|
|
36
|
+
opacity: 1;
|
|
37
|
+
}
|
|
38
|
+
50% {
|
|
39
|
+
opacity: 0.3;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@media (prefers-reduced-motion: reduce) {
|
|
44
|
+
.muka-recording-bar__dot {
|
|
45
|
+
animation: none;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RecordingBar = void 0;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const Waveform_1 = require("../Waveform");
|
|
7
|
+
const VoiceRecorder_1 = require("../VoiceRecorder");
|
|
8
|
+
require("./RecordingBar.css");
|
|
9
|
+
/**
|
|
10
|
+
* RecordingBar — drop-in content for `ChatComposer.recordingSlot` while a voice
|
|
11
|
+
* note is being recorded. A pulsing record dot, an elapsed timer, and the live
|
|
12
|
+
* `Waveform`. Muka delegates this slot to the app, but ships this default so
|
|
13
|
+
* consumers don't rebuild it. Feed it straight from `useVoiceRecorder`
|
|
14
|
+
* (`elapsedMs`, `livePeaks`). Tokens only; the label comes via props.
|
|
15
|
+
*/
|
|
16
|
+
const RecordingBar = ({ elapsedMs, livePeaks, recordingLabel = 'Recording', className = '', }) => {
|
|
17
|
+
const classes = ['muka-recording-bar', className].filter(Boolean).join(' ');
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: classes, role: "status", "aria-label": recordingLabel, children: [(0, jsx_runtime_1.jsx)("span", { className: "muka-recording-bar__dot", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("span", { className: "muka-recording-bar__time", children: (0, VoiceRecorder_1.formatClock)(elapsedMs / 1000) }), (0, jsx_runtime_1.jsx)("div", { className: "muka-recording-bar__wave", children: (0, jsx_runtime_1.jsx)(Waveform_1.Waveform, { peaks: livePeaks, progress: 1 }) })] }));
|
|
19
|
+
};
|
|
20
|
+
exports.RecordingBar = RecordingBar;
|
|
21
|
+
exports.default = exports.RecordingBar;
|
|
22
|
+
//# sourceMappingURL=RecordingBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordingBar.js","sourceRoot":"","sources":["../../../../components/RecordingBar/RecordingBar.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;AAGb,0CAAuC;AACvC,oDAA+C;AAC/C,8BAA4B;AAgB5B;;;;;;GAMG;AACI,MAAM,YAAY,GAAgC,CAAC,EACxD,SAAS,EACT,SAAS,EACT,cAAc,GAAG,WAAW,EAC5B,SAAS,GAAG,EAAE,GACf,EAAE,EAAE;IACH,MAAM,OAAO,GAAG,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5E,OAAO,CACL,iCAAK,SAAS,EAAE,OAAO,EAAE,IAAI,EAAC,QAAQ,gBAAa,cAAc,aAC/D,iCAAM,SAAS,EAAC,yBAAyB,iBAAa,MAAM,GAAG,EAC/D,iCAAM,SAAS,EAAC,0BAA0B,YAAE,IAAA,2BAAW,EAAC,SAAS,GAAG,IAAI,CAAC,GAAQ,EACjF,gCAAK,SAAS,EAAC,0BAA0B,YACvC,uBAAC,mBAAQ,IAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAI,GACvC,IACF,CACP,CAAC;AACJ,CAAC,CAAC;AAjBW,QAAA,YAAY,gBAiBvB;AAEF,kBAAe,oBAAY,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = exports.RecordingBar = void 0;
|
|
7
|
+
var RecordingBar_1 = require("./RecordingBar");
|
|
8
|
+
Object.defineProperty(exports, "RecordingBar", { enumerable: true, get: function () { return RecordingBar_1.RecordingBar; } });
|
|
9
|
+
var RecordingBar_2 = require("./RecordingBar");
|
|
10
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(RecordingBar_2).default; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../components/RecordingBar/index.ts"],"names":[],"mappings":";;;;;;AAAA,+CAAsE;AAA7D,4GAAA,YAAY,OAAA;AACrB,+CAAyC;AAAhC,wHAAA,OAAO,OAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* VoiceMessage Component Styles */
|
|
2
|
+
|
|
3
|
+
.muka-voice-message {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: var(--spacing-3);
|
|
7
|
+
width: 100%;
|
|
8
|
+
min-width: min(16rem, 60vw);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.muka-voice-message__wave {
|
|
12
|
+
flex: 1 1 auto;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.muka-voice-message__time {
|
|
17
|
+
flex: 0 0 auto;
|
|
18
|
+
white-space: nowrap;
|
|
19
|
+
font-size: var(--text-label-sm-fontSize, 0.75rem);
|
|
20
|
+
line-height: var(--text-label-sm-lineHeight, 1);
|
|
21
|
+
font-variant-numeric: tabular-nums;
|
|
22
|
+
color: var(--color-text-subtle-default);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* On the tinted own bubble the surface is the action color, so the timer flips
|
|
26
|
+
* to the inverse text token for contrast. */
|
|
27
|
+
.muka-voice-message--own .muka-voice-message__time {
|
|
28
|
+
color: var(--color-text-default-inverse);
|
|
29
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.VoiceMessage = void 0;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const Button_1 = require("../Button");
|
|
8
|
+
const Icon_1 = require("../Icon");
|
|
9
|
+
const Waveform_1 = require("../Waveform");
|
|
10
|
+
const VoiceRecorder_1 = require("../VoiceRecorder");
|
|
11
|
+
require("./VoiceMessage.css");
|
|
12
|
+
/**
|
|
13
|
+
* VoiceMessage — inline play/pause player for a sent voice note.
|
|
14
|
+
*
|
|
15
|
+
* Composes a Muka `Button` with the shared token-based `Waveform`; the media
|
|
16
|
+
* stays with the app (`src` is whatever URL it hands over — Muka never fetches
|
|
17
|
+
* or signs it). Play/pause only: there is no transcription/speech-to-text.
|
|
18
|
+
*/
|
|
19
|
+
const VoiceMessage = ({ src, durationSec, peaks, variant, playLabel = 'Play voice message', pauseLabel = 'Pause voice message', unavailableLabel = 'Voice message unavailable', className = '', }) => {
|
|
20
|
+
const audioRef = (0, react_1.useRef)(null);
|
|
21
|
+
const [playing, setPlaying] = (0, react_1.useState)(false);
|
|
22
|
+
const [currentSec, setCurrentSec] = (0, react_1.useState)(0);
|
|
23
|
+
const [totalSec, setTotalSec] = (0, react_1.useState)(durationSec);
|
|
24
|
+
(0, react_1.useEffect)(() => {
|
|
25
|
+
const audio = audioRef.current;
|
|
26
|
+
if (!audio)
|
|
27
|
+
return;
|
|
28
|
+
const onTime = () => setCurrentSec(audio.currentTime);
|
|
29
|
+
const onLoaded = () => {
|
|
30
|
+
if (Number.isFinite(audio.duration) && audio.duration > 0) {
|
|
31
|
+
setTotalSec(audio.duration);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const onEnded = () => {
|
|
35
|
+
setPlaying(false);
|
|
36
|
+
setCurrentSec(0);
|
|
37
|
+
};
|
|
38
|
+
audio.addEventListener('timeupdate', onTime);
|
|
39
|
+
audio.addEventListener('loadedmetadata', onLoaded);
|
|
40
|
+
audio.addEventListener('ended', onEnded);
|
|
41
|
+
return () => {
|
|
42
|
+
audio.removeEventListener('timeupdate', onTime);
|
|
43
|
+
audio.removeEventListener('loadedmetadata', onLoaded);
|
|
44
|
+
audio.removeEventListener('ended', onEnded);
|
|
45
|
+
};
|
|
46
|
+
}, [src]);
|
|
47
|
+
const toggle = () => {
|
|
48
|
+
const audio = audioRef.current;
|
|
49
|
+
if (!audio)
|
|
50
|
+
return;
|
|
51
|
+
if (playing) {
|
|
52
|
+
audio.pause();
|
|
53
|
+
setPlaying(false);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
void audio
|
|
57
|
+
.play()
|
|
58
|
+
.then(() => setPlaying(true))
|
|
59
|
+
.catch(() => setPlaying(false));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const effectiveTotal = totalSec || durationSec;
|
|
63
|
+
const progress = effectiveTotal > 0 ? Math.min(1, currentSec / effectiveTotal) : 0;
|
|
64
|
+
const remaining = playing || currentSec > 0 ? effectiveTotal - currentSec : effectiveTotal;
|
|
65
|
+
// On own (tinted) bubbles the surface is the action color, so the played bars
|
|
66
|
+
// use the inverse text token for contrast; elsewhere the action color reads
|
|
67
|
+
// well against the light card.
|
|
68
|
+
const activeColor = variant === 'own'
|
|
69
|
+
? 'var(--color-text-default-inverse)'
|
|
70
|
+
: 'var(--color-action-default)';
|
|
71
|
+
const inactiveColor = variant === 'own'
|
|
72
|
+
? 'var(--color-black-alpha-3, rgba(0, 0, 0, 0.25))'
|
|
73
|
+
: 'var(--color-border-contrast)';
|
|
74
|
+
const classes = [
|
|
75
|
+
'muka-voice-message',
|
|
76
|
+
`muka-voice-message--${variant}`,
|
|
77
|
+
className,
|
|
78
|
+
]
|
|
79
|
+
.filter(Boolean)
|
|
80
|
+
.join(' ');
|
|
81
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: classes, children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { variant: variant === 'own' ? 'secondary' : 'primary', size: "md", iconOnly: true, "aria-label": playing ? pauseLabel : playLabel, onClick: toggle, disabled: !src, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: playing ? 'pause' : 'play', variant: "fill", size: "sm" }) }), (0, jsx_runtime_1.jsx)("div", { className: "muka-voice-message__wave", children: (0, jsx_runtime_1.jsx)(Waveform_1.Waveform, { peaks: peaks, progress: progress, activeColor: activeColor, inactiveColor: inactiveColor, "aria-label": src ? undefined : unavailableLabel }) }), (0, jsx_runtime_1.jsx)("span", { className: "muka-voice-message__time", children: (0, VoiceRecorder_1.formatClock)(remaining) }), src && (0, jsx_runtime_1.jsx)("audio", { ref: audioRef, src: src, preload: "metadata" })] }));
|
|
82
|
+
};
|
|
83
|
+
exports.VoiceMessage = VoiceMessage;
|
|
84
|
+
exports.default = exports.VoiceMessage;
|
|
85
|
+
//# sourceMappingURL=VoiceMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceMessage.js","sourceRoot":"","sources":["../../../../components/VoiceMessage/VoiceMessage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = exports.VoiceMessage = void 0;
|
|
7
|
+
var VoiceMessage_1 = require("./VoiceMessage");
|
|
8
|
+
Object.defineProperty(exports, "VoiceMessage", { enumerable: true, get: function () { return VoiceMessage_1.VoiceMessage; } });
|
|
9
|
+
var VoiceMessage_2 = require("./VoiceMessage");
|
|
10
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(VoiceMessage_2).default; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../components/VoiceMessage/index.ts"],"names":[],"mappings":";;;;;;AAAA,+CAIwB;AAHtB,4GAAA,YAAY,OAAA;AAId,+CAAyC;AAAhC,wHAAA,OAAO,OAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.VOICE_PEAK_COUNT = void 0;
|
|
5
|
+
exports.downsamplePeaks = downsamplePeaks;
|
|
6
|
+
exports.formatClock = formatClock;
|
|
7
|
+
exports.isVoiceRecordingSupported = isVoiceRecordingSupported;
|
|
8
|
+
/**
|
|
9
|
+
* Audio helpers shared by the voice-recording hook and the players.
|
|
10
|
+
*
|
|
11
|
+
* Pure, DOM-light utilities: peak downsampling for a compact persisted waveform
|
|
12
|
+
* and a clock formatter for the recorder timer / player countdown. No upload,
|
|
13
|
+
* no network, no speech-to-text.
|
|
14
|
+
*/
|
|
15
|
+
/** Default number of persisted waveform bars. Apps may override per clip. */
|
|
16
|
+
exports.VOICE_PEAK_COUNT = 48;
|
|
17
|
+
/**
|
|
18
|
+
* Downsample a stream of amplitude samples (each already 0..1) into exactly
|
|
19
|
+
* `count` normalized peaks by taking the max of each bucket, then scaling so the
|
|
20
|
+
* loudest bar reaches 1. Pure — unit-testable independently of the DOM.
|
|
21
|
+
*/
|
|
22
|
+
function downsamplePeaks(samples, count = exports.VOICE_PEAK_COUNT) {
|
|
23
|
+
if (samples.length === 0 || count <= 0)
|
|
24
|
+
return [];
|
|
25
|
+
const buckets = new Array(count).fill(0);
|
|
26
|
+
const size = samples.length / count;
|
|
27
|
+
for (let i = 0; i < count; i += 1) {
|
|
28
|
+
const start = Math.floor(i * size);
|
|
29
|
+
const end = Math.min(samples.length, Math.max(start + 1, Math.floor((i + 1) * size)));
|
|
30
|
+
let peak = 0;
|
|
31
|
+
for (let j = start; j < end; j += 1) {
|
|
32
|
+
const v = Math.abs(samples[j]);
|
|
33
|
+
if (v > peak)
|
|
34
|
+
peak = v;
|
|
35
|
+
}
|
|
36
|
+
buckets[i] = peak;
|
|
37
|
+
}
|
|
38
|
+
const max = buckets.reduce((m, v) => (v > m ? v : m), 0);
|
|
39
|
+
if (max <= 0)
|
|
40
|
+
return buckets;
|
|
41
|
+
return buckets.map((v) => Math.min(1, v / max));
|
|
42
|
+
}
|
|
43
|
+
/** Format a number of seconds as `m:ss` for the recorder timer / player. */
|
|
44
|
+
function formatClock(totalSeconds) {
|
|
45
|
+
const safe = Number.isFinite(totalSeconds) && totalSeconds > 0
|
|
46
|
+
? Math.floor(totalSeconds)
|
|
47
|
+
: 0;
|
|
48
|
+
const minutes = Math.floor(safe / 60);
|
|
49
|
+
const seconds = safe % 60;
|
|
50
|
+
const paddedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
|
51
|
+
return `${minutes}:${paddedSeconds}`;
|
|
52
|
+
}
|
|
53
|
+
/** True when this browser can record audio at all (SSR-safe). */
|
|
54
|
+
function isVoiceRecordingSupported() {
|
|
55
|
+
return (typeof window !== 'undefined' &&
|
|
56
|
+
typeof navigator !== 'undefined' &&
|
|
57
|
+
!!navigator.mediaDevices &&
|
|
58
|
+
typeof navigator.mediaDevices.getUserMedia === 'function' &&
|
|
59
|
+
typeof MediaRecorder !== 'undefined');
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../../../components/VoiceRecorder/audio.ts"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;AAkBb,0CAuBC;AAGD,kCASC;AAGD,8DAQC;AA9DD;;;;;;GAMG;AAEH,6EAA6E;AAChE,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAEnC;;;;GAIG;AACH,SAAgB,eAAe,CAC7B,OAAiB,EACjB,QAAgB,wBAAgB;IAEhC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClD,MAAM,OAAO,GAAa,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAClB,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAChD,CAAC;QACF,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,IAAI;gBAAE,IAAI,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACpB,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzD,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC;IAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,4EAA4E;AAC5E,SAAgB,WAAW,CAAC,YAAoB;IAC9C,MAAM,IAAI,GACR,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC;QAC/C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;QAC1B,CAAC,CAAC,CAAC,CAAC;IACR,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,MAAM,aAAa,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC;IAClE,OAAO,GAAG,OAAO,IAAI,aAAa,EAAE,CAAC;AACvC,CAAC;AAED,iEAAiE;AACjE,SAAgB,yBAAyB;IACvC,OAAO,CACL,OAAO,MAAM,KAAK,WAAW;QAC7B,OAAO,SAAS,KAAK,WAAW;QAChC,CAAC,CAAC,SAAS,CAAC,YAAY;QACxB,OAAO,SAAS,CAAC,YAAY,CAAC,YAAY,KAAK,UAAU;QACzD,OAAO,aAAa,KAAK,WAAW,CACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = exports.VOICE_PEAK_COUNT = exports.isVoiceRecordingSupported = exports.formatClock = exports.downsamplePeaks = exports.useVoiceRecorder = void 0;
|
|
7
|
+
var useVoiceRecorder_1 = require("./useVoiceRecorder");
|
|
8
|
+
Object.defineProperty(exports, "useVoiceRecorder", { enumerable: true, get: function () { return useVoiceRecorder_1.useVoiceRecorder; } });
|
|
9
|
+
var audio_1 = require("./audio");
|
|
10
|
+
Object.defineProperty(exports, "downsamplePeaks", { enumerable: true, get: function () { return audio_1.downsamplePeaks; } });
|
|
11
|
+
Object.defineProperty(exports, "formatClock", { enumerable: true, get: function () { return audio_1.formatClock; } });
|
|
12
|
+
Object.defineProperty(exports, "isVoiceRecordingSupported", { enumerable: true, get: function () { return audio_1.isVoiceRecordingSupported; } });
|
|
13
|
+
Object.defineProperty(exports, "VOICE_PEAK_COUNT", { enumerable: true, get: function () { return audio_1.VOICE_PEAK_COUNT; } });
|
|
14
|
+
var useVoiceRecorder_2 = require("./useVoiceRecorder");
|
|
15
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(useVoiceRecorder_2).default; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../components/VoiceRecorder/index.ts"],"names":[],"mappings":";;;;;;AAAA,uDAK4B;AAJ1B,oHAAA,gBAAgB,OAAA;AAKlB,iCAKiB;AAJf,wGAAA,eAAe,OAAA;AACf,oGAAA,WAAW,OAAA;AACX,kHAAA,yBAAyB,OAAA;AACzB,yGAAA,gBAAgB,OAAA;AAElB,uDAA6C;AAApC,4HAAA,OAAO,OAAA"}
|