@exode-team/react-recorder 1.1.2 → 1.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorder.styled.d.ts","sourceRoot":"","sources":["../../src/components/AudioRecorder.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,SAAS,KAMrB,CAAC"}
1
+ {"version":3,"file":"AudioRecorder.styled.d.ts","sourceRoot":"","sources":["../../src/components/AudioRecorder.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,SAAS,KAKrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingShell.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH,UAAU,KAAK;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAGD,QAAA,MAAM,cAAc,GAAI,OAAO,KAAK,QAyHnC,CAAC;AAGF,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"RecordingShell.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,UAAU,KAAK;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAGD,QAAA,MAAM,cAAc,GAAI,OAAO,KAAK,QA6HnC,CAAC;AAGF,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingShell.styled.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAQnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAQjB,CAAC;AAEF,eAAO,MAAM,YAAY,KA2CxB,CAAC;AAEF,eAAO,MAAM,QAAQ,KAOpB,CAAC;AAEF,eAAO,MAAM,IAAI,KAMhB,CAAC;AAEF,eAAO,MAAM,GAAG,KAOf,CAAC;AAEF,eAAO,MAAM,KAAK,KAKjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAyBtB,CAAC;AAEF,eAAO,MAAM,WAAW,KAMvB,CAAC;AAEF,eAAO,MAAM,OAAO,KAoBnB,CAAC"}
1
+ {"version":3,"file":"RecordingShell.styled.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAOnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAQjB,CAAC;AAEF,eAAO,MAAM,YAAY,KA2CxB,CAAC;AAEF,eAAO,MAAM,QAAQ,KAOpB,CAAC;AAEF,eAAO,MAAM,IAAI,KAMhB,CAAC;AAEF,eAAO,MAAM,GAAG,KAOf,CAAC;AAEF,eAAO,MAAM,KAAK,KAKjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAyBtB,CAAC;AAEF,eAAO,MAAM,WAAW,KAMvB,CAAC;AAEF,eAAO,MAAM,OAAO,KAoBnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceMessagePlayer/VoiceMessagePlayer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAeD,QAAA,MAAM,kBAAkB,KAsLtB,CAAC;AAGH,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"VoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceMessagePlayer/VoiceMessagePlayer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAeD,QAAA,MAAM,kBAAkB,KA8MtB,CAAC;AAGH,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -10,7 +10,7 @@ interface PreviewBarsProps {
10
10
  recordingTime: number;
11
11
  previewLevels: number[];
12
12
  timelineLevels: number[];
13
- getVisibleBarsCount: () => number;
13
+ visibleBarsCount: number;
14
14
  }
15
15
  declare const PreviewBars: (props: PreviewBarsProps) => any;
16
16
  export { PreviewBars };
@@ -1 +1 @@
1
- {"version":3,"file":"PreviewBars.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/PreviewBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,gBAAgB;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,mBAAmB,EAAE,MAAM,MAAM,CAAC;CACrC;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,QA0E3C,CAAC;AAGF,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"PreviewBars.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/PreviewBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,gBAAgB;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,QA0E3C,CAAC;AAGF,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -5,7 +5,7 @@
5
5
  */
6
6
  interface TimelineBarsProps {
7
7
  timelineLevels: number[];
8
- getVisibleBarsCount: () => number;
8
+ visibleBarsCount: number;
9
9
  }
10
10
  declare const TimelineBars: (props: TimelineBarsProps) => any;
11
11
  export { TimelineBars };
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineBars.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/TimelineBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,iBAAiB;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,mBAAmB,EAAE,MAAM,MAAM,CAAC;CACrC;AAGD,QAAA,MAAM,YAAY,GAAI,OAAO,iBAAiB,QAkC7C,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"TimelineBars.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/TimelineBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,iBAAiB;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAGD,QAAA,MAAM,YAAY,GAAI,OAAO,iBAAiB,QAkC7C,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceRecorderInput.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/VoiceRecorderInput.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAuBrE,UAAU,KAAK;IACX,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,QAAA,MAAM,kBAAkB,GAAI,OAAO,KAAK,QAsGvC,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"VoiceRecorderInput.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/VoiceRecorderInput.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAuBrE,UAAU,KAAK;IACX,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,QAAA,MAAM,kBAAkB,GAAI,OAAO,KAAK,QAmIvC,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceRecorderInput.styled.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/VoiceRecorderInput.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAOnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAkBxB,CAAC;AAEF,eAAO,MAAM,WAAW,KASvB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,UAAU,KAKtB,CAAC;AAEF,eAAO,MAAM,UAAU,KA0BtB,CAAC;AAEF,eAAO,MAAM,YAAY,KAUxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAMjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAuBtB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,eAAe,KAqB3B,CAAC;AAEF,eAAO,MAAM,WAAW,KAcvB,CAAC"}
1
+ {"version":3,"file":"VoiceRecorderInput.styled.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceRecorderInput/VoiceRecorderInput.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAOnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAcxB,CAAC;AAEF,eAAO,MAAM,WAAW,KASvB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,UAAU,KAMtB,CAAC;AAEF,eAAO,MAAM,UAAU,KA0BtB,CAAC;AAEF,eAAO,MAAM,YAAY,KAUxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAMjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAuBtB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,eAAe,KAqB3B,CAAC;AAEF,eAAO,MAAM,WAAW,KAcvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioBlobLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioBlobLoader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,UAAU,yBAAyB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,UAAU,wBAAwB;IAC9B,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,QAAA,MAAM,kBAAkB,GAAI,SAAS,yBAAyB,KAAG,wBAgIhE,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"useAudioBlobLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioBlobLoader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,UAAU,yBAAyB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,UAAU,wBAAwB;IAC9B,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,QAAA,MAAM,kBAAkB,GAAI,SAAS,yBAAyB,KAAG,wBAoIhE,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -784,6 +784,7 @@ const useAudioBlobLoader = (options) => {
784
784
  const audioRef = React.useRef(null);
785
785
  const objectUrlRef = React.useRef(null);
786
786
  const abortControllerRef = React.useRef(null);
787
+ const failedSrcRef = React.useRef(null);
787
788
  const callbacksRef = React.useRef(playbackCallbacks);
788
789
  callbacksRef.current = playbackCallbacks;
789
790
  const createAudioFromBlob = React.useCallback((blob) => {
@@ -820,7 +821,7 @@ const useAudioBlobLoader = (options) => {
820
821
  }, [waveformData, createAudioFromBlob]);
821
822
  const ensureAudioLoaded = React.useCallback(async () => {
822
823
  var _a;
823
- if (audioRef.current) {
824
+ if (audioRef.current || failedSrcRef.current === src) {
824
825
  return;
825
826
  }
826
827
  if (preloadedBlob) {
@@ -851,6 +852,7 @@ const useAudioBlobLoader = (options) => {
851
852
  if (error instanceof DOMException && error.name === 'AbortError') {
852
853
  return;
853
854
  }
855
+ failedSrcRef.current = src;
854
856
  console.warn('[voice-player] Failed to load audio', error);
855
857
  }
856
858
  finally {
@@ -861,6 +863,7 @@ const useAudioBlobLoader = (options) => {
861
863
  }, [src, waveformData, preloadedBlob, mountFromBlob, createAudioFromBlob]);
862
864
  /** Cleanup on src change or unmount */
863
865
  React.useEffect(() => {
866
+ failedSrcRef.current = null;
864
867
  return () => {
865
868
  var _a;
866
869
  (_a = abortControllerRef.current) === null || _a === void 0 ? void 0 : _a.abort();
@@ -1190,7 +1193,6 @@ const useAudioRecorderHandlers = (options) => {
1190
1193
  const Container = styled.div `
1191
1194
  position: relative;
1192
1195
  width: 100%;
1193
- padding: 16px;
1194
1196
  transition: color 200ms ease, background-color 200ms ease;
1195
1197
  color: var(--text_primary, #0a0a0a);
1196
1198
  `;
@@ -1275,29 +1277,28 @@ const Wrapper$1 = styled.div `
1275
1277
  gap: 12px;
1276
1278
  padding: 10px 14px;
1277
1279
  border-radius: 9999px;
1278
- background: var(--background_content, #ffffff);
1279
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text_primary, #0a0a0a) 6%, transparent);
1280
+ background: var(--background_hover, color-mix(in srgb, var(--text_primary, #0a0a0a) 6%, transparent));
1280
1281
  `;
1281
1282
  const CancelButton$1 = styled.button `
1282
- width: 36px;
1283
- height: 36px;
1283
+ width: 38px;
1284
+ height: 38px;
1284
1285
  display: inline-flex;
1285
1286
  align-items: center;
1286
1287
  justify-content: center;
1287
- border-radius: 18px;
1288
- background: transparent;
1288
+ border-radius: 19px;
1289
+ background: color-mix(in srgb, var(--exode_red) 10%, transparent);
1289
1290
  border: 0;
1291
+ flex-shrink: 0;
1290
1292
  color: color-mix(in srgb, var(--text_primary, #0a0a0a) 54%, transparent);
1291
1293
  cursor: pointer;
1292
- transition: color 160ms ease, background-color 160ms ease;
1294
+ transition: transform 160ms ease;
1293
1295
 
1294
- &:hover {
1295
- background-color: color-mix(in srgb, var(--text_primary, #0a0a0a) 12%, transparent);
1296
- color: color-mix(in srgb, var(--text_primary, #0a0a0a) 76%, transparent);
1296
+ &:hover:not(:disabled) {
1297
+ transform: translateY(-1px);
1297
1298
  }
1298
1299
 
1299
- &:active {
1300
- background-color: color-mix(in srgb, var(--text_primary, #0a0a0a) 18%, transparent);
1300
+ &:active:not(:disabled) {
1301
+ transform: translateY(0);
1301
1302
  }
1302
1303
  `;
1303
1304
  const Track = styled.div `
@@ -1305,7 +1306,7 @@ const Track = styled.div `
1305
1306
  display: flex;
1306
1307
  align-items: center;
1307
1308
  gap: 12px;
1308
- padding: 8px 12px;
1309
+ padding: 8px 10px;
1309
1310
  border-radius: 9999px;
1310
1311
  background: color-mix(in srgb, var(--text_primary, #0a0a0a) 10%, transparent);
1311
1312
  `;
@@ -1469,7 +1470,9 @@ const RecordingShell = (props) => {
1469
1470
  return formatTime(0);
1470
1471
  }, [formatTime, hasRecording, isPlaying, playbackDuration, playbackTime, recordingTime]);
1471
1472
  const recordButtonDisabled = isSending;
1472
- const recordButtonIcon = !isRecording || isPaused ? jsxRuntime.jsx(icons.Icon16Microphone, {}) : jsxRuntime.jsx(icons.Icon16Square, {});
1473
+ const recordButtonIcon = !isRecording || isPaused
1474
+ ? jsxRuntime.jsx(icons.Icon16Microphone, { width: 24, height: 24 })
1475
+ : jsxRuntime.jsx(icons.Icon16Pause, { width: 24, height: 24 });
1473
1476
  const recordButtonVariant = !isRecording || isPaused ? 'resume' : 'record';
1474
1477
  const recordButtonAria = !isRecording
1475
1478
  ? startAriaLabel
@@ -1478,14 +1481,16 @@ const RecordingShell = (props) => {
1478
1481
  : pauseRecordingAriaLabel || stopAriaLabel;
1479
1482
  const canShowPlayback = !isRecording || isPaused;
1480
1483
  const playbackDisabled = !hasRecording && !isRecording;
1481
- const playbackIcon = isPlaying ? jsxRuntime.jsx(icons.Icon16Pause, {}) : jsxRuntime.jsx(icons.Icon16Play, {});
1484
+ const playbackIcon = isPlaying
1485
+ ? jsxRuntime.jsx(icons.Icon16Pause, { width: 24, height: 24 })
1486
+ : jsxRuntime.jsx(icons.Icon16Play, { width: 24, height: 24 });
1482
1487
  const playbackAria = isPlaying ? pausePlaybackAriaLabel : playAriaLabel;
1483
1488
  const sendDisabled = isSending || (!hasRecording && !isRecording);
1484
- return (jsxRuntime.jsxs(Wrapper$1, { children: [jsxRuntime.jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsxRuntime.jsx(icons.Icon28CancelOutline, { width: 20, height: 20 }) }), jsxRuntime.jsxs(Track, { children: [jsxRuntime.jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsxRuntime.jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsxRuntime.jsx(Waveform, { "$expanded": canShowPlayback, children: jsxRuntime.jsx(WaveformBars, { values: waveformValues, divider: 100, scale: 42, minHeight: 6, styleInterpolator: ({ normalized }) => ({
1489
+ return (jsxRuntime.jsxs(Wrapper$1, { children: [jsxRuntime.jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsxRuntime.jsx(icons.Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 24, height: 24, style: { minWidth: 24 } }) }), jsxRuntime.jsxs(Track, { children: [jsxRuntime.jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsxRuntime.jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsxRuntime.jsx(Waveform, { "$expanded": canShowPlayback, children: jsxRuntime.jsx(WaveformBars, { values: waveformValues, divider: 100, scale: 42, minHeight: 6, styleInterpolator: ({ normalized }) => ({
1485
1490
  height: `${12 + normalized / 2}px`,
1486
1491
  maxHeight: '34px',
1487
1492
  opacity: 0.38 + Math.min(0.5, normalized / 120),
1488
- }) }) }), jsxRuntime.jsx(Timer$1, { children: displayTime })] }), jsxRuntime.jsx(SendButton$1, { type: "button", onClick: onSend, disabled: sendDisabled, "aria-label": sendAriaLabel, children: isSending ? (jsxRuntime.jsx(SpinnerSlot, { children: jsxRuntime.jsx(Spinner, {}) })) : (jsxRuntime.jsx(icons.Icon28SendOutline, { width: 20, height: 20 })) })] }));
1493
+ }) }) }), jsxRuntime.jsx(Timer$1, { children: displayTime })] }), jsxRuntime.jsx(SendButton$1, { type: "button", onClick: onSend, disabled: sendDisabled, "aria-label": sendAriaLabel, children: isSending ? (jsxRuntime.jsx(SpinnerSlot, { children: jsxRuntime.jsx(Spinner, {}) })) : (jsxRuntime.jsx(icons.Icon28SendOutline, { width: 24, height: 24 })) })] }));
1489
1494
  };
1490
1495
 
1491
1496
  /**
@@ -1745,8 +1750,8 @@ const useVoiceRecorderInput = (options) => {
1745
1750
 
1746
1751
  const PreviewBars = (props) => {
1747
1752
  var _a, _b;
1748
- const { isPlaying, playbackTime, lastDuration, previewLevels, recordingTime, timelineLevels, getVisibleBarsCount, } = props;
1749
- const maxBars = getVisibleBarsCount();
1753
+ const { isPlaying, playbackTime, lastDuration, previewLevels, recordingTime, timelineLevels, visibleBarsCount, } = props;
1754
+ const maxBars = visibleBarsCount;
1750
1755
  const sourceLevels = timelineLevels.length > 0
1751
1756
  ? timelineLevels
1752
1757
  : previewLevels;
@@ -1790,8 +1795,8 @@ const PreviewBars = (props) => {
1790
1795
  };
1791
1796
 
1792
1797
  const TimelineBars = (props) => {
1793
- const { timelineLevels, getVisibleBarsCount } = props;
1794
- const maxBars = getVisibleBarsCount();
1798
+ const { timelineLevels, visibleBarsCount } = props;
1799
+ const maxBars = visibleBarsCount;
1795
1800
  const visible = timelineLevels.slice(-maxBars);
1796
1801
  const padded = [
1797
1802
  ...visible,
@@ -1836,15 +1841,11 @@ const CancelButton = styled.button `
1836
1841
  border-radius: 16px;
1837
1842
  background: transparent;
1838
1843
  border: 0;
1844
+ margin-right: 4px;
1839
1845
  flex-shrink: 0;
1840
1846
  color: color-mix(in srgb, var(--text_primary, #0a0a0a) 45%, transparent);
1841
1847
  cursor: pointer;
1842
1848
  transition: color 160ms ease, background-color 160ms ease;
1843
-
1844
- &:hover {
1845
- background-color: color-mix(in srgb, var(--text_primary, #0a0a0a) 8%, transparent);
1846
- color: color-mix(in srgb, var(--text_primary, #0a0a0a) 72%, transparent);
1847
- }
1848
1849
  `;
1849
1850
  const RecordTrack = styled.div `
1850
1851
  flex: 1;
@@ -1860,7 +1861,8 @@ const RecordTrack = styled.div `
1860
1861
  const ButtonSlot = styled.div `
1861
1862
  display: flex;
1862
1863
  align-items: center;
1863
- gap: 2px;
1864
+ gap: 4px;
1865
+ padding: 2px;
1864
1866
  flex-shrink: 0;
1865
1867
  `;
1866
1868
  const StopButton = styled.button `
@@ -1997,19 +1999,39 @@ const VoiceRecorderInput = (props) => {
1997
1999
  const waveformRef = React.useRef(null);
1998
2000
  const { recorder, isSending, isPreview, timelineLevels, lastDurationRef, handleResume, handlePause, handleCancel, handleSendRequest, } = useVoiceRecorderInput(inputOptions);
1999
2001
  const { isPlaying, isRecording, recordingTime, hasRecording, previewLevels, playbackTime, formatTime, togglePlayback, } = recorder;
2000
- const getVisibleBarsCount = React.useCallback(() => {
2002
+ const [visibleBarsCount, setVisibleBarsCount] = React.useState(0);
2003
+ const measureBars = () => {
2001
2004
  const el = waveformRef.current;
2002
2005
  if (!el) {
2003
- return 60;
2006
+ return;
2004
2007
  }
2005
- return Math.floor(el.clientWidth / (TIMELINE_BAR_WIDTH + TIMELINE_BAR_GAP));
2008
+ setVisibleBarsCount(Math.floor(el.clientWidth / (TIMELINE_BAR_WIDTH + TIMELINE_BAR_GAP)));
2009
+ };
2010
+ /** Sync recalc before paint — catches layout shifts from button changes */
2011
+ React.useLayoutEffect(measureBars);
2012
+ /** ResizeObserver for external size changes (window resize, container resize) */
2013
+ React.useEffect(() => {
2014
+ const el = waveformRef.current;
2015
+ if (!el) {
2016
+ return;
2017
+ }
2018
+ let rafId = 0;
2019
+ const observer = new ResizeObserver(() => {
2020
+ cancelAnimationFrame(rafId);
2021
+ rafId = requestAnimationFrame(measureBars);
2022
+ });
2023
+ observer.observe(el);
2024
+ return () => {
2025
+ cancelAnimationFrame(rafId);
2026
+ observer.disconnect();
2027
+ };
2006
2028
  }, []);
2007
2029
  const displayTime = (isPreview && isPlaying)
2008
2030
  ? formatTime(playbackTime)
2009
2031
  : formatTime(recordingTime || lastDurationRef.current);
2010
- return (jsxRuntime.jsxs(Wrapper, { className: className, children: [jsxRuntime.jsx(CancelButton, { type: "button", onClick: handleCancel, "aria-label": "Cancel", children: jsxRuntime.jsx(icons.Icon28CancelOutline, { width: 20, height: 20 }) }), jsxRuntime.jsxs(RecordTrack, { children: [jsxRuntime.jsx(ButtonSlot, { children: isPreview ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MicIndicator, { type: "button", onClick: handleResume, "aria-label": "Resume recording", children: jsxRuntime.jsx(icons.Icon20VoiceOutline, { width: 14, height: 14 }) }), jsxRuntime.jsx(PlayPauseButton, { type: "button", onClick: togglePlayback, "aria-label": isPlaying ? 'Pause' : 'Play', children: isPlaying
2032
+ return (jsxRuntime.jsxs(Wrapper, { className: className, children: [jsxRuntime.jsx(CancelButton, { type: "button", onClick: handleCancel, "aria-label": "Cancel", children: jsxRuntime.jsx(icons.Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 28, height: 28, style: { minWidth: 28 } }) }), jsxRuntime.jsxs(RecordTrack, { children: [jsxRuntime.jsx(ButtonSlot, { children: isPreview ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MicIndicator, { type: "button", onClick: handleResume, "aria-label": "Resume recording", children: jsxRuntime.jsx(icons.Icon20Voice, { width: 14, height: 14 }) }), jsxRuntime.jsx(PlayPauseButton, { type: "button", onClick: togglePlayback, "aria-label": isPlaying ? 'Pause' : 'Play', children: isPlaying
2011
2033
  ? jsxRuntime.jsx(icons.Icon16Pause, { width: 14, height: 14 })
2012
- : jsxRuntime.jsx(icons.Icon16Play, { width: 14, height: 14 }) })] })) : (jsxRuntime.jsx(StopButton, { type: "button", onClick: handlePause, "aria-label": "Pause recording", children: jsxRuntime.jsx(icons.Icon16Square, { width: 12, height: 12 }) })) }), jsxRuntime.jsx(WaveformArea, { ref: waveformRef, children: isPreview ? (jsxRuntime.jsx(PreviewBars, { timelineLevels: timelineLevels, previewLevels: previewLevels, isPlaying: isPlaying, playbackTime: playbackTime, recordingTime: recordingTime, lastDuration: lastDurationRef.current, getVisibleBarsCount: getVisibleBarsCount })) : (jsxRuntime.jsx(TimelineBars, { timelineLevels: timelineLevels, getVisibleBarsCount: getVisibleBarsCount })) }), jsxRuntime.jsx(Timer, { children: displayTime })] }), jsxRuntime.jsx(SendButton, { type: "button", onClick: handleSendRequest, disabled: isSending || (!hasRecording && !isRecording), "aria-label": "Send", children: isSending ? (jsxRuntime.jsx(SpinnerIcon, {})) : (jsxRuntime.jsx(icons.Icon28SendOutline, {})) })] }));
2034
+ : jsxRuntime.jsx(icons.Icon16Play, { width: 14, height: 14 }) })] })) : (jsxRuntime.jsx(StopButton, { type: "button", onClick: handlePause, "aria-label": "Pause recording", children: jsxRuntime.jsx(icons.Icon16Pause, { width: 14, height: 14 }) })) }), jsxRuntime.jsx(WaveformArea, { ref: waveformRef, children: isPreview ? (jsxRuntime.jsx(PreviewBars, { timelineLevels: timelineLevels, previewLevels: previewLevels, isPlaying: isPlaying, playbackTime: playbackTime, recordingTime: recordingTime, lastDuration: lastDurationRef.current, visibleBarsCount: visibleBarsCount })) : (jsxRuntime.jsx(TimelineBars, { timelineLevels: timelineLevels, visibleBarsCount: visibleBarsCount })) }), jsxRuntime.jsx(Timer, { children: displayTime })] }), jsxRuntime.jsx(SendButton, { type: "button", onClick: handleSendRequest, disabled: isSending || (!hasRecording && !isRecording), "aria-label": "Send", children: isSending ? (jsxRuntime.jsx(SpinnerIcon, {})) : (jsxRuntime.jsx(icons.Icon28SendOutline, {})) })] }));
2013
2035
  };
2014
2036
 
2015
2037
  /**
@@ -2185,11 +2207,29 @@ const VoiceMessagePlayer = React.forwardRef((props, ref) => {
2185
2207
  return VoicePlaybackChain.register(chainId, () => play());
2186
2208
  }
2187
2209
  }, [chainId, play]);
2188
- /** Measure track width once after mount */
2189
- React.useLayoutEffect(() => {
2210
+ const measureTrackWidth = () => {
2190
2211
  if (trackRef.current) {
2191
2212
  setTrackWidth(trackRef.current.clientWidth);
2192
2213
  }
2214
+ };
2215
+ /** Sync recalc before paint — catches layout shifts */
2216
+ React.useLayoutEffect(measureTrackWidth);
2217
+ /** ResizeObserver for external size changes (window resize, container resize) */
2218
+ React.useEffect(() => {
2219
+ const el = trackRef.current;
2220
+ if (!el) {
2221
+ return;
2222
+ }
2223
+ let rafId = 0;
2224
+ const observer = new ResizeObserver(() => {
2225
+ cancelAnimationFrame(rafId);
2226
+ rafId = requestAnimationFrame(measureTrackWidth);
2227
+ });
2228
+ observer.observe(el);
2229
+ return () => {
2230
+ cancelAnimationFrame(rafId);
2231
+ observer.disconnect();
2232
+ };
2193
2233
  }, []);
2194
2234
  const displayTime = isPlaying
2195
2235
  ? formatTime(currentTime)