@mieweb/ui 0.1.0 → 0.2.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.
Files changed (88) hide show
  1. package/LICENSE +39 -15
  2. package/README.md +9 -1
  3. package/dist/brands/index.cjs +7 -7
  4. package/dist/brands/index.js +2 -2
  5. package/dist/{chunk-CLNOI5J7.js → chunk-4SMSH4OY.js} +4 -4
  6. package/dist/chunk-4SMSH4OY.js.map +1 -0
  7. package/dist/chunk-4T2ZNPTC.js +220 -0
  8. package/dist/chunk-4T2ZNPTC.js.map +1 -0
  9. package/dist/chunk-5T3AWNHG.cjs +471 -0
  10. package/dist/chunk-5T3AWNHG.cjs.map +1 -0
  11. package/dist/{chunk-LEE3NMNP.cjs → chunk-5UUL5EEO.cjs} +131 -81
  12. package/dist/chunk-5UUL5EEO.cjs.map +1 -0
  13. package/dist/chunk-74K3RRU7.cjs +4 -0
  14. package/dist/{chunk-ZO46CFVN.cjs.map → chunk-74K3RRU7.cjs.map} +1 -1
  15. package/dist/{chunk-VWXGUNBR.cjs → chunk-AKTUXJPI.cjs} +107 -18
  16. package/dist/chunk-AKTUXJPI.cjs.map +1 -0
  17. package/dist/chunk-BV75DAKO.cjs +245 -0
  18. package/dist/chunk-BV75DAKO.cjs.map +1 -0
  19. package/dist/{chunk-6DP6RKUA.cjs → chunk-CLJZHS7Y.cjs} +2 -2
  20. package/dist/{chunk-6DP6RKUA.cjs.map → chunk-CLJZHS7Y.cjs.map} +1 -1
  21. package/dist/{chunk-NH2JVQ6V.cjs → chunk-I7L6CQXR.cjs} +21 -9
  22. package/dist/chunk-I7L6CQXR.cjs.map +1 -0
  23. package/dist/{chunk-BR2XGATJ.cjs → chunk-NNEFAUHV.cjs} +4 -4
  24. package/dist/chunk-NNEFAUHV.cjs.map +1 -0
  25. package/dist/{chunk-KJOFWJHV.js → chunk-QSMMFATL.js} +131 -81
  26. package/dist/chunk-QSMMFATL.js.map +1 -0
  27. package/dist/{chunk-FIUNOH6W.js → chunk-S4DK5WN6.js} +2 -2
  28. package/dist/{chunk-FIUNOH6W.js.map → chunk-S4DK5WN6.js.map} +1 -1
  29. package/dist/chunk-SCV7C55E.cjs +11 -0
  30. package/dist/chunk-SCV7C55E.cjs.map +1 -0
  31. package/dist/{chunk-D5IBXXF2.js → chunk-SD44QJIP.js} +20 -8
  32. package/dist/chunk-SD44QJIP.js.map +1 -0
  33. package/dist/{chunk-QBWVTJKF.js → chunk-UBRDKNLQ.js} +107 -18
  34. package/dist/chunk-UBRDKNLQ.js.map +1 -0
  35. package/dist/chunk-V2DF2GUE.js +3 -0
  36. package/dist/{chunk-ZQ4XMJH7.js.map → chunk-V2DF2GUE.js.map} +1 -1
  37. package/dist/chunk-VSQF22GL.js +9 -0
  38. package/dist/chunk-VSQF22GL.js.map +1 -0
  39. package/dist/chunk-XVZ4SLQB.js +447 -0
  40. package/dist/chunk-XVZ4SLQB.js.map +1 -0
  41. package/dist/components/AudioPlayer/index.cjs +6 -6
  42. package/dist/components/AudioPlayer/index.d.cts +5 -1
  43. package/dist/components/AudioPlayer/index.d.ts +5 -1
  44. package/dist/components/AudioPlayer/index.js +1 -1
  45. package/dist/components/Modal/index.cjs +11 -10
  46. package/dist/components/Modal/index.js +3 -2
  47. package/dist/components/RecordButton/index.cjs +4 -8
  48. package/dist/components/RecordButton/index.d.cts +57 -44
  49. package/dist/components/RecordButton/index.d.ts +57 -44
  50. package/dist/components/RecordButton/index.js +1 -1
  51. package/dist/components/Select/index.cjs +3 -4
  52. package/dist/components/Select/index.js +1 -2
  53. package/dist/components/Slider/index.cjs +25 -0
  54. package/dist/components/Slider/index.cjs.map +1 -0
  55. package/dist/components/Slider/index.d.cts +82 -0
  56. package/dist/components/Slider/index.d.ts +82 -0
  57. package/dist/components/Slider/index.js +4 -0
  58. package/dist/components/Slider/index.js.map +1 -0
  59. package/dist/components/Spinner/index.d.cts +1 -1
  60. package/dist/components/Spinner/index.d.ts +1 -1
  61. package/dist/hooks/index.cjs +3 -2
  62. package/dist/hooks/index.js +2 -1
  63. package/dist/index.cjs +1899 -1238
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.d.cts +68 -25
  66. package/dist/index.d.ts +68 -25
  67. package/dist/index.js +1793 -1148
  68. package/dist/index.js.map +1 -1
  69. package/dist/styles.css +1 -1
  70. package/dist/utils/index.cjs +6 -1
  71. package/dist/utils/index.d.cts +14 -1
  72. package/dist/utils/index.d.ts +14 -1
  73. package/dist/utils/index.js +2 -1
  74. package/package.json +7 -7
  75. package/dist/chunk-BR2XGATJ.cjs.map +0 -1
  76. package/dist/chunk-CLNOI5J7.js.map +0 -1
  77. package/dist/chunk-D5IBXXF2.js.map +0 -1
  78. package/dist/chunk-FQ5G7J24.js +0 -297
  79. package/dist/chunk-FQ5G7J24.js.map +0 -1
  80. package/dist/chunk-HLW3XD5R.cjs +0 -322
  81. package/dist/chunk-HLW3XD5R.cjs.map +0 -1
  82. package/dist/chunk-KJOFWJHV.js.map +0 -1
  83. package/dist/chunk-LEE3NMNP.cjs.map +0 -1
  84. package/dist/chunk-NH2JVQ6V.cjs.map +0 -1
  85. package/dist/chunk-QBWVTJKF.js.map +0 -1
  86. package/dist/chunk-VWXGUNBR.cjs.map +0 -1
  87. package/dist/chunk-ZO46CFVN.cjs +0 -4
  88. package/dist/chunk-ZQ4XMJH7.js +0 -3
@@ -204,11 +204,16 @@ function Waveform({
204
204
  onSeek,
205
205
  waveColor,
206
206
  progressColor,
207
- height = 64
207
+ height = 64,
208
+ showHoverCursor = false,
209
+ onHoverTimeChange,
210
+ cursorColor = "var(--color-red-500, rgb(239, 68, 68))"
208
211
  }) {
209
212
  const containerRef = React.useRef(null);
210
213
  const wavesurferRef = React.useRef(null);
211
214
  const [isLoaded, setIsLoaded] = React.useState(false);
215
+ const [isHovering, setIsHovering] = React.useState(false);
216
+ const [hoverPosition, setHoverPosition] = React.useState(0);
212
217
  React.useEffect(() => {
213
218
  if (!containerRef.current) return;
214
219
  const initWaveSurfer = async () => {
@@ -227,7 +232,7 @@ function Waveform({
227
232
  barRadius: 2,
228
233
  height,
229
234
  normalize: true,
230
- interact: true
235
+ interact: !showHoverCursor
231
236
  });
232
237
  wavesurferRef.current.on("ready", () => {
233
238
  setIsLoaded(true);
@@ -239,9 +244,11 @@ function Waveform({
239
244
  wavesurferRef.current.on("seeking", () => {
240
245
  onTimeUpdate(wavesurferRef.current.getCurrentTime());
241
246
  });
242
- wavesurferRef.current.on("interaction", () => {
243
- onSeek(wavesurferRef.current.getCurrentTime());
244
- });
247
+ if (!showHoverCursor) {
248
+ wavesurferRef.current.on("interaction", () => {
249
+ onSeek(wavesurferRef.current.getCurrentTime());
250
+ });
251
+ }
245
252
  wavesurferRef.current.on("finish", () => {
246
253
  onFinish();
247
254
  });
@@ -257,7 +264,7 @@ function Waveform({
257
264
  wavesurferRef.current = null;
258
265
  }
259
266
  };
260
- }, [src]);
267
+ }, [src, showHoverCursor]);
261
268
  React.useEffect(() => {
262
269
  if (!wavesurferRef.current || !isLoaded) return;
263
270
  if (isPlaying) {
@@ -270,15 +277,77 @@ function Waveform({
270
277
  if (!wavesurferRef.current || !isLoaded) return;
271
278
  wavesurferRef.current.setPlaybackRate(playbackRate);
272
279
  }, [playbackRate, isLoaded]);
280
+ const handleMouseMove = showHoverCursor ? (e) => {
281
+ if (!containerRef.current || !wavesurferRef.current || !isLoaded)
282
+ return;
283
+ const rect = containerRef.current.getBoundingClientRect();
284
+ const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
285
+ const percentage = x / rect.width;
286
+ const duration = wavesurferRef.current.getDuration();
287
+ setHoverPosition(percentage * 100);
288
+ onHoverTimeChange?.(percentage * duration);
289
+ } : void 0;
290
+ const handleMouseEnter = showHoverCursor ? () => setIsHovering(true) : void 0;
291
+ const handleMouseLeave = showHoverCursor ? () => {
292
+ setIsHovering(false);
293
+ setHoverPosition(0);
294
+ onHoverTimeChange?.(null);
295
+ } : void 0;
296
+ const handleClick = showHoverCursor ? (e) => {
297
+ if (!containerRef.current || !wavesurferRef.current || !isLoaded)
298
+ return;
299
+ const rect = containerRef.current.getBoundingClientRect();
300
+ const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
301
+ const percentage = x / rect.width;
302
+ wavesurferRef.current.seekTo(percentage);
303
+ onSeek(wavesurferRef.current.getDuration() * percentage);
304
+ onHoverTimeChange?.(null);
305
+ } : void 0;
306
+ const handleKeyDown = showHoverCursor ? (e) => {
307
+ if (!wavesurferRef.current || !isLoaded) return;
308
+ const duration = wavesurferRef.current.getDuration();
309
+ const currentTime = wavesurferRef.current.getCurrentTime();
310
+ const step = duration * 0.05;
311
+ if (e.key === "ArrowRight") {
312
+ e.preventDefault();
313
+ const newTime = Math.min(currentTime + step, duration);
314
+ wavesurferRef.current.seekTo(newTime / duration);
315
+ onSeek(newTime);
316
+ } else if (e.key === "ArrowLeft") {
317
+ e.preventDefault();
318
+ const newTime = Math.max(currentTime - step, 0);
319
+ wavesurferRef.current.seekTo(newTime / duration);
320
+ onSeek(newTime);
321
+ }
322
+ } : void 0;
273
323
  return /* @__PURE__ */ jsx(
274
324
  "div",
275
325
  {
276
326
  ref: containerRef,
327
+ role: showHoverCursor ? "slider" : void 0,
328
+ "aria-label": showHoverCursor ? "Audio progress" : void 0,
329
+ "aria-valuemin": showHoverCursor ? 0 : void 0,
330
+ "aria-valuemax": showHoverCursor && wavesurferRef.current ? wavesurferRef.current.getDuration() : void 0,
331
+ "aria-valuenow": showHoverCursor && wavesurferRef.current ? wavesurferRef.current.getCurrentTime() : void 0,
332
+ tabIndex: showHoverCursor ? 0 : void 0,
277
333
  className: cn(
278
- "w-full rounded-lg bg-neutral-100 dark:bg-neutral-800",
334
+ "relative w-full rounded-lg bg-neutral-100 dark:bg-neutral-800",
335
+ showHoverCursor && "cursor-pointer",
279
336
  !isLoaded && "animate-pulse"
280
337
  ),
281
- style: { height }
338
+ style: { height },
339
+ onMouseMove: handleMouseMove,
340
+ onMouseEnter: handleMouseEnter,
341
+ onMouseLeave: handleMouseLeave,
342
+ onClick: handleClick,
343
+ onKeyDown: handleKeyDown,
344
+ children: showHoverCursor && isHovering && isLoaded && /* @__PURE__ */ jsx(
345
+ "div",
346
+ {
347
+ className: "pointer-events-none absolute top-0 bottom-0 z-10 w-0.5",
348
+ style: { left: `${hoverPosition}%`, backgroundColor: cursorColor }
349
+ }
350
+ )
282
351
  }
283
352
  );
284
353
  }
@@ -296,6 +365,8 @@ function AudioPlayer({
296
365
  waveColor,
297
366
  progressColor,
298
367
  waveformHeight = 64,
368
+ showWaveformHoverCursor = true,
369
+ waveformCursorColor,
299
370
  disabled = false,
300
371
  className,
301
372
  "aria-label": ariaLabel,
@@ -311,6 +382,7 @@ function AudioPlayer({
311
382
  const [duration, setDuration] = React.useState(0);
312
383
  const [playbackRate, setPlaybackRate] = React.useState(1);
313
384
  const [audioInitialized, setAudioInitialized] = React.useState(false);
385
+ const [hoverTime, setHoverTime] = React.useState(null);
314
386
  const audioRef = React.useRef(null);
315
387
  const isPlaying = state === "playing";
316
388
  const isLoading = state === "loading";
@@ -449,6 +521,9 @@ function AudioPlayer({
449
521
  const handleWaveformSeek = React.useCallback((time) => {
450
522
  setCurrentTime(time);
451
523
  }, []);
524
+ const handleHoverTimeChange = React.useCallback((time) => {
525
+ setHoverTime(time);
526
+ }, []);
452
527
  const iconSize = size === "sm" ? "h-3.5 w-3.5" : size === "lg" ? "h-5 w-5" : "h-4 w-4";
453
528
  const getAriaLabel = () => {
454
529
  if (ariaLabel) return ariaLabel;
@@ -467,13 +542,24 @@ function AudioPlayer({
467
542
  children: isLoading ? /* @__PURE__ */ jsx(SpinnerIcon, { className: iconSize }) : isPlaying ? /* @__PURE__ */ jsx(PauseIcon, { className: iconSize }) : /* @__PURE__ */ jsx(PlayIcon, { className: iconSize })
468
543
  }
469
544
  );
470
- const renderTime = () => {
545
+ const renderTime = (useHoverTime = false) => {
471
546
  if (!showTime) return null;
472
- return /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-neutral-500 tabular-nums dark:text-neutral-400", children: [
473
- formatTime(currentTime),
474
- " / ",
475
- formatTime(duration)
476
- ] });
547
+ const displayTime = useHoverTime && hoverTime !== null ? hoverTime : currentTime;
548
+ const isShowingHoverTime = useHoverTime && hoverTime !== null;
549
+ return /* @__PURE__ */ jsxs(
550
+ "span",
551
+ {
552
+ className: cn(
553
+ "font-mono text-xs tabular-nums",
554
+ isShowingHoverTime ? "text-primary-600 dark:text-primary-400" : "text-neutral-500 dark:text-neutral-400"
555
+ ),
556
+ children: [
557
+ formatTime(displayTime),
558
+ " / ",
559
+ formatTime(duration)
560
+ ]
561
+ }
562
+ );
477
563
  };
478
564
  const renderPlaybackRateControl = () => {
479
565
  if (!showPlaybackRate) return null;
@@ -529,13 +615,16 @@ function AudioPlayer({
529
615
  onSeek: handleWaveformSeek,
530
616
  waveColor,
531
617
  progressColor,
532
- height: waveformHeight
618
+ height: waveformHeight,
619
+ showHoverCursor: showWaveformHoverCursor,
620
+ onHoverTimeChange: handleHoverTimeChange,
621
+ cursorColor: waveformCursorColor
533
622
  }
534
623
  ),
535
624
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
536
625
  renderPlayButton(),
537
626
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center justify-between", children: [
538
- renderTime(),
627
+ renderTime(true),
539
628
  renderPlaybackRateControl()
540
629
  ] })
541
630
  ] })
@@ -544,5 +633,5 @@ function AudioPlayer({
544
633
  AudioPlayer.displayName = "AudioPlayer";
545
634
 
546
635
  export { AudioPlayer, ProgressBar, audioPlayerVariants, formatTime, playButtonVariants };
547
- //# sourceMappingURL=chunk-QBWVTJKF.js.map
548
- //# sourceMappingURL=chunk-QBWVTJKF.js.map
636
+ //# sourceMappingURL=chunk-UBRDKNLQ.js.map
637
+ //# sourceMappingURL=chunk-UBRDKNLQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AudioPlayer/AudioPlayer.tsx"],"names":[],"mappings":"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","file":"chunk-UBRDKNLQ.js","sourcesContent":["import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Types & Interfaces\n// ============================================================================\n\nexport type AudioPlayerState =\n | 'idle'\n | 'loading'\n | 'playing'\n | 'paused'\n | 'error';\n\nexport interface AudioPlayerProps extends VariantProps<\n typeof audioPlayerVariants\n> {\n /** Audio source URL */\n src: string;\n /** Title/label for the audio (used for accessibility and display) */\n title?: string;\n /** Callback when playback state changes */\n onStateChange?: (state: AudioPlayerState) => void;\n /** Callback when playback ends */\n onEnded?: () => void;\n /** Callback when an error occurs */\n onError?: (error: Error) => void;\n /** Callback when time updates during playback */\n onTimeUpdate?: (currentTime: number, duration: number) => void;\n /** Whether to show the time display */\n showTime?: boolean;\n /** Whether to show the duration (for inline variant) */\n showDuration?: boolean;\n /** Waveform color (for waveform variant) */\n waveColor?: string;\n /** Progress/played waveform color (for waveform variant) */\n progressColor?: string;\n /** Height of the waveform (for waveform variant) */\n waveformHeight?: number;\n /** Whether to show hover cursor on waveform for click-to-seek preview (for waveform variant) */\n showWaveformHoverCursor?: boolean;\n /** Color of the hover cursor line (for waveform variant) */\n waveformCursorColor?: string;\n /** Whether the player is disabled */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n /** Accessible label */\n 'aria-label'?: string;\n /** Playback speed options */\n playbackRates?: number[];\n /** Whether to show playback speed control */\n showPlaybackRate?: boolean;\n}\n\n// ============================================================================\n// Variants\n// ============================================================================\n\nconst audioPlayerVariants = cva('', {\n variants: {\n variant: {\n inline: 'inline-flex items-center gap-2',\n compact: [\n 'flex items-center gap-3 p-3',\n 'rounded-lg border border-border',\n 'bg-card text-card-foreground',\n ],\n waveform: [\n 'flex flex-col gap-3 p-4',\n 'rounded-xl border border-border',\n 'bg-card text-card-foreground',\n ],\n },\n size: {\n sm: '',\n md: '',\n lg: '',\n },\n },\n compoundVariants: [\n { variant: 'compact', size: 'sm', class: 'p-2 gap-2' },\n { variant: 'compact', size: 'lg', class: 'p-4 gap-4' },\n { variant: 'waveform', size: 'sm', class: 'p-3 gap-2' },\n { variant: 'waveform', size: 'lg', class: 'p-5 gap-4' },\n ],\n defaultVariants: {\n variant: 'compact',\n size: 'md',\n },\n});\n\nconst playButtonVariants = cva(\n [\n 'inline-flex items-center justify-center',\n 'rounded-full transition-all duration-200',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n 'disabled:pointer-events-none disabled:opacity-50',\n 'active:scale-95',\n ],\n {\n variants: {\n variant: {\n inline: [\n 'text-neutral-500 hover:text-neutral-700 hover:bg-neutral-100',\n 'dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-800',\n ],\n compact: [\n 'bg-primary-600 text-white',\n 'hover:bg-primary-700',\n 'active:bg-primary-800',\n ],\n waveform: [\n 'bg-primary-600 text-white',\n 'hover:bg-primary-700',\n 'active:bg-primary-800',\n ],\n },\n size: {\n sm: 'h-7 w-7',\n md: 'h-9 w-9',\n lg: 'h-11 w-11',\n },\n },\n defaultVariants: {\n variant: 'compact',\n size: 'md',\n },\n }\n);\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nexport function formatTime(seconds: number): string {\n if (!isFinite(seconds) || isNaN(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\n// ============================================================================\n// Icons\n// ============================================================================\n\nfunction PlayIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n );\n}\n\nfunction PauseIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\" />\n </svg>\n );\n}\n\nfunction SpinnerIcon({ className }: { className?: string }) {\n return (\n <svg\n className={cn('animate-spin', className)}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n}\n\n// ============================================================================\n// Progress Bar Component (for compact variant)\n// ============================================================================\n\ninterface ProgressBarProps {\n currentTime: number;\n duration: number;\n onSeek: (time: number) => void;\n disabled?: boolean;\n}\n\nfunction ProgressBar({\n currentTime,\n duration,\n onSeek,\n disabled,\n}: ProgressBarProps) {\n const progressRef = React.useRef<HTMLDivElement>(null);\n const progress = duration > 0 ? (currentTime / duration) * 100 : 0;\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled || !progressRef.current || duration <= 0) return;\n const rect = progressRef.current.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const percentage = x / rect.width;\n onSeek(percentage * duration);\n };\n\n return (\n <div\n ref={progressRef}\n role=\"slider\"\n aria-label=\"Audio progress\"\n aria-valuemin={0}\n aria-valuemax={duration}\n aria-valuenow={currentTime}\n aria-valuetext={`${formatTime(currentTime)} of ${formatTime(duration)}`}\n tabIndex={disabled ? -1 : 0}\n className={cn(\n 'relative h-1.5 flex-1 cursor-pointer rounded-full bg-neutral-200 dark:bg-neutral-700',\n disabled && 'cursor-not-allowed opacity-50'\n )}\n onClick={handleClick}\n onKeyDown={(e) => {\n if (disabled) return;\n const step = duration * 0.05; // 5% steps\n if (e.key === 'ArrowRight') {\n onSeek(Math.min(currentTime + step, duration));\n } else if (e.key === 'ArrowLeft') {\n onSeek(Math.max(currentTime - step, 0));\n }\n }}\n >\n <div\n className=\"bg-primary-600 absolute inset-y-0 left-0 rounded-full transition-all\"\n style={{ width: `${progress}%` }}\n />\n <div\n className=\"bg-primary-600 absolute top-1/2 h-3 w-3 -translate-y-1/2 rounded-full shadow-sm transition-all\"\n style={{ left: `calc(${progress}% - 6px)` }}\n />\n </div>\n );\n}\n\n// ============================================================================\n// Waveform Component (lazy-loaded WaveSurfer)\n// ============================================================================\n\ninterface WaveformProps {\n src: string;\n isPlaying: boolean;\n playbackRate?: number;\n onReady: (duration: number) => void;\n onTimeUpdate: (time: number) => void;\n onFinish: () => void;\n onSeek: (time: number) => void;\n waveColor?: string;\n progressColor?: string;\n height?: number;\n showHoverCursor?: boolean;\n onHoverTimeChange?: (time: number | null) => void;\n cursorColor?: string;\n}\n\nfunction Waveform({\n src,\n isPlaying,\n playbackRate = 1,\n onReady,\n onTimeUpdate,\n onFinish,\n onSeek,\n waveColor,\n progressColor,\n height = 64,\n showHoverCursor = false,\n onHoverTimeChange,\n cursorColor = 'var(--color-red-500, rgb(239, 68, 68))',\n}: WaveformProps) {\n const containerRef = React.useRef<HTMLDivElement>(null);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const wavesurferRef = React.useRef<any>(null);\n const [isLoaded, setIsLoaded] = React.useState(false);\n const [isHovering, setIsHovering] = React.useState(false);\n const [hoverPosition, setHoverPosition] = React.useState(0);\n\n // Initialize WaveSurfer\n React.useEffect(() => {\n if (!containerRef.current) return;\n\n const initWaveSurfer = async () => {\n try {\n const WaveSurfer = (await import('wavesurfer.js')).default;\n\n if (wavesurferRef.current) {\n wavesurferRef.current.destroy();\n }\n\n wavesurferRef.current = WaveSurfer.create({\n container: containerRef.current!,\n waveColor: waveColor || '#d1d5db',\n progressColor: progressColor || 'var(--color-primary-600, #2563eb)',\n cursorColor: 'transparent',\n barWidth: 2,\n barGap: 2,\n barRadius: 2,\n height,\n normalize: true,\n interact: !showHoverCursor,\n });\n\n wavesurferRef.current.on('ready', () => {\n setIsLoaded(true);\n onReady(wavesurferRef.current.getDuration());\n });\n\n wavesurferRef.current.on('audioprocess', () => {\n onTimeUpdate(wavesurferRef.current.getCurrentTime());\n });\n\n wavesurferRef.current.on('seeking', () => {\n onTimeUpdate(wavesurferRef.current.getCurrentTime());\n });\n\n if (!showHoverCursor) {\n wavesurferRef.current.on('interaction', () => {\n onSeek(wavesurferRef.current.getCurrentTime());\n });\n }\n\n wavesurferRef.current.on('finish', () => {\n onFinish();\n });\n\n wavesurferRef.current.load(src);\n } catch (error) {\n console.error('Failed to load WaveSurfer:', error);\n }\n };\n\n initWaveSurfer();\n\n return () => {\n if (wavesurferRef.current) {\n wavesurferRef.current.destroy();\n wavesurferRef.current = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [src, showHoverCursor]);\n\n // Handle play/pause\n React.useEffect(() => {\n if (!wavesurferRef.current || !isLoaded) return;\n\n if (isPlaying) {\n wavesurferRef.current.play();\n } else {\n wavesurferRef.current.pause();\n }\n }, [isPlaying, isLoaded]);\n\n // Handle playback rate changes\n React.useEffect(() => {\n if (!wavesurferRef.current || !isLoaded) return;\n wavesurferRef.current.setPlaybackRate(playbackRate);\n }, [playbackRate, isLoaded]);\n\n // Hover cursor handlers\n const handleMouseMove = showHoverCursor\n ? (e: React.MouseEvent<HTMLDivElement>) => {\n if (!containerRef.current || !wavesurferRef.current || !isLoaded)\n return;\n const rect = containerRef.current.getBoundingClientRect();\n const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));\n const percentage = x / rect.width;\n const duration = wavesurferRef.current.getDuration();\n setHoverPosition(percentage * 100);\n onHoverTimeChange?.(percentage * duration);\n }\n : undefined;\n\n const handleMouseEnter = showHoverCursor\n ? () => setIsHovering(true)\n : undefined;\n\n const handleMouseLeave = showHoverCursor\n ? () => {\n setIsHovering(false);\n setHoverPosition(0);\n onHoverTimeChange?.(null);\n }\n : undefined;\n\n const handleClick = showHoverCursor\n ? (e: React.MouseEvent<HTMLDivElement>) => {\n if (!containerRef.current || !wavesurferRef.current || !isLoaded)\n return;\n const rect = containerRef.current.getBoundingClientRect();\n const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));\n const percentage = x / rect.width;\n wavesurferRef.current.seekTo(percentage);\n onSeek(wavesurferRef.current.getDuration() * percentage);\n onHoverTimeChange?.(null);\n }\n : undefined;\n\n const handleKeyDown = showHoverCursor\n ? (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!wavesurferRef.current || !isLoaded) return;\n const duration = wavesurferRef.current.getDuration();\n const currentTime = wavesurferRef.current.getCurrentTime();\n const step = duration * 0.05; // 5% steps\n\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n const newTime = Math.min(currentTime + step, duration);\n wavesurferRef.current.seekTo(newTime / duration);\n onSeek(newTime);\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n const newTime = Math.max(currentTime - step, 0);\n wavesurferRef.current.seekTo(newTime / duration);\n onSeek(newTime);\n }\n }\n : undefined;\n\n return (\n <div\n ref={containerRef}\n role={showHoverCursor ? 'slider' : undefined}\n aria-label={showHoverCursor ? 'Audio progress' : undefined}\n aria-valuemin={showHoverCursor ? 0 : undefined}\n aria-valuemax={\n showHoverCursor && wavesurferRef.current\n ? wavesurferRef.current.getDuration()\n : undefined\n }\n aria-valuenow={\n showHoverCursor && wavesurferRef.current\n ? wavesurferRef.current.getCurrentTime()\n : undefined\n }\n tabIndex={showHoverCursor ? 0 : undefined}\n className={cn(\n 'relative w-full rounded-lg bg-neutral-100 dark:bg-neutral-800',\n showHoverCursor && 'cursor-pointer',\n !isLoaded && 'animate-pulse'\n )}\n style={{ height }}\n onMouseMove={handleMouseMove}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n >\n {/* Hover cursor line */}\n {showHoverCursor && isHovering && isLoaded && (\n <div\n className=\"pointer-events-none absolute top-0 bottom-0 z-10 w-0.5\"\n style={{ left: `${hoverPosition}%`, backgroundColor: cursorColor }}\n />\n )}\n </div>\n );\n}\n\n// ============================================================================\n// Main AudioPlayer Component\n// ============================================================================\n\n/**\n * A versatile audio player component with multiple display variants.\n *\n * @example\n * ```tsx\n * // Inline - minimal, just play button and duration\n * <AudioPlayer src=\"/audio.mp3\" variant=\"inline\" showDuration />\n *\n * // Compact - play button, progress bar, and time\n * <AudioPlayer src=\"/audio.mp3\" variant=\"compact\" showTime />\n *\n * // Waveform - full visualization with WaveSurfer\n * <AudioPlayer src=\"/audio.mp3\" variant=\"waveform\" showTime />\n * ```\n */\nfunction AudioPlayer({\n src,\n title,\n variant = 'compact',\n size = 'md',\n onStateChange,\n onEnded,\n onError,\n onTimeUpdate,\n showTime = true,\n showDuration = true,\n waveColor,\n progressColor,\n waveformHeight = 64,\n showWaveformHoverCursor = true,\n waveformCursorColor,\n disabled = false,\n className,\n 'aria-label': ariaLabel,\n playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 2],\n showPlaybackRate = false,\n /** Whether to preload audio (set to false for lists with many items) */\n preload = false,\n /** Fallback duration in seconds to display before audio is loaded */\n fallbackDuration,\n}: AudioPlayerProps & { preload?: boolean; fallbackDuration?: number }) {\n const [state, setState] = React.useState<AudioPlayerState>('idle');\n const [currentTime, setCurrentTime] = React.useState(0);\n const [duration, setDuration] = React.useState(0);\n const [playbackRate, setPlaybackRate] = React.useState(1);\n const [audioInitialized, setAudioInitialized] = React.useState(false);\n const [hoverTime, setHoverTime] = React.useState<number | null>(null);\n const audioRef = React.useRef<globalThis.HTMLAudioElement | null>(null);\n\n const isPlaying = state === 'playing';\n const isLoading = state === 'loading';\n\n // Update state helper\n const updateState = React.useCallback(\n (newState: AudioPlayerState) => {\n setState(newState);\n onStateChange?.(newState);\n },\n [onStateChange]\n );\n\n // Initialize audio element (for non-waveform variants)\n const initAudio = React.useCallback(() => {\n if (variant === 'waveform' || audioInitialized) return null;\n\n const audio = new globalThis.Audio(src);\n audioRef.current = audio;\n setAudioInitialized(true);\n\n audio.addEventListener('loadstart', () => updateState('loading'));\n audio.addEventListener('canplay', () => {\n updateState('idle');\n });\n audio.addEventListener('loadedmetadata', () => {\n setDuration(audio.duration);\n });\n audio.addEventListener('timeupdate', () => {\n setCurrentTime(audio.currentTime);\n onTimeUpdate?.(audio.currentTime, audio.duration);\n });\n audio.addEventListener('ended', () => {\n updateState('idle');\n setCurrentTime(0);\n onEnded?.();\n });\n audio.addEventListener('error', () => {\n updateState('error');\n onError?.(new Error('Failed to load audio'));\n });\n\n return audio;\n }, [\n src,\n variant,\n audioInitialized,\n updateState,\n onTimeUpdate,\n onEnded,\n onError,\n ]);\n\n // Auto-initialize if preload is true\n React.useEffect(() => {\n if (preload && !audioInitialized && variant !== 'waveform') {\n initAudio();\n }\n }, [preload, audioInitialized, variant, initAudio]);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n if (audioRef.current) {\n audioRef.current.pause();\n audioRef.current.src = '';\n }\n };\n }, []);\n\n // Handle playback rate changes\n React.useEffect(() => {\n if (audioRef.current) {\n audioRef.current.playbackRate = playbackRate;\n }\n }, [playbackRate]);\n\n const handlePlay = React.useCallback(() => {\n if (disabled) return;\n\n // Waveform variant uses WaveSurfer for playback - just toggle state\n if (variant === 'waveform') {\n if (isLoading) return;\n updateState(isPlaying ? 'paused' : 'playing');\n return;\n }\n\n // Lazy initialize audio on first play\n if (!audioInitialized && !isLoading) {\n const audio = initAudio();\n if (audio) {\n updateState('loading');\n audio.addEventListener(\n 'canplay',\n () => {\n audio.play().catch((error) => {\n updateState('error');\n onError?.(error);\n });\n updateState('playing');\n },\n { once: true }\n );\n }\n return;\n }\n\n if (isLoading) return;\n\n if (isPlaying) {\n if (audioRef.current) {\n audioRef.current.pause();\n }\n updateState('paused');\n } else {\n if (audioRef.current) {\n audioRef.current.play().catch((error) => {\n updateState('error');\n onError?.(error);\n });\n updateState('playing');\n }\n }\n }, [\n disabled,\n variant,\n audioInitialized,\n isLoading,\n isPlaying,\n initAudio,\n updateState,\n onError,\n ]);\n\n const handleSeek = React.useCallback((time: number) => {\n if (audioRef.current) {\n audioRef.current.currentTime = time;\n setCurrentTime(time);\n }\n }, []);\n\n // Waveform callbacks\n const handleWaveformReady = React.useCallback((dur: number) => {\n setDuration(dur);\n setState('idle');\n }, []);\n\n const handleWaveformTimeUpdate = React.useCallback(\n (time: number) => {\n setCurrentTime(time);\n onTimeUpdate?.(time, duration);\n },\n [duration, onTimeUpdate]\n );\n\n const handleWaveformFinish = React.useCallback(() => {\n updateState('idle');\n setCurrentTime(0);\n onEnded?.();\n }, [updateState, onEnded]);\n\n const handleWaveformSeek = React.useCallback((time: number) => {\n setCurrentTime(time);\n }, []);\n\n const handleHoverTimeChange = React.useCallback((time: number | null) => {\n setHoverTime(time);\n }, []);\n\n const iconSize =\n size === 'sm' ? 'h-3.5 w-3.5' : size === 'lg' ? 'h-5 w-5' : 'h-4 w-4';\n\n const getAriaLabel = () => {\n if (ariaLabel) return ariaLabel;\n if (title) return `${isPlaying ? 'Pause' : 'Play'} ${title}`;\n return isPlaying ? 'Pause audio' : 'Play audio';\n };\n\n const renderPlayButton = () => (\n <button\n type=\"button\"\n onClick={handlePlay}\n disabled={disabled || isLoading}\n className={cn(playButtonVariants({ variant, size }))}\n aria-label={getAriaLabel()}\n aria-pressed={isPlaying}\n >\n {isLoading ? (\n <SpinnerIcon className={iconSize} />\n ) : isPlaying ? (\n <PauseIcon className={iconSize} />\n ) : (\n <PlayIcon className={iconSize} />\n )}\n </button>\n );\n\n const renderTime = (useHoverTime = false) => {\n if (!showTime) return null;\n const displayTime =\n useHoverTime && hoverTime !== null ? hoverTime : currentTime;\n const isShowingHoverTime = useHoverTime && hoverTime !== null;\n return (\n <span\n className={cn(\n 'font-mono text-xs tabular-nums',\n isShowingHoverTime\n ? 'text-primary-600 dark:text-primary-400'\n : 'text-neutral-500 dark:text-neutral-400'\n )}\n >\n {formatTime(displayTime)} / {formatTime(duration)}\n </span>\n );\n };\n\n const renderPlaybackRateControl = () => {\n if (!showPlaybackRate) return null;\n return (\n <select\n value={playbackRate}\n onChange={(e) => setPlaybackRate(Number(e.target.value))}\n className=\"rounded border border-neutral-200 bg-transparent px-1 py-0.5 text-xs dark:border-neutral-700\"\n aria-label=\"Playback speed\"\n >\n {playbackRates.map((rate) => (\n <option key={rate} value={rate}>\n {rate}x\n </option>\n ))}\n </select>\n );\n };\n\n // ============================================================================\n // Inline Variant\n // ============================================================================\n if (variant === 'inline') {\n const displayDuration = duration > 0 ? duration : (fallbackDuration ?? 0);\n return (\n <div className={cn(audioPlayerVariants({ variant, size }), className)}>\n {renderPlayButton()}\n {title && (\n <span className=\"text-sm font-medium text-neutral-700 dark:text-neutral-300\">\n {title}\n </span>\n )}\n {showDuration && displayDuration > 0 && (\n <span className=\"font-mono text-xs text-neutral-500 tabular-nums dark:text-neutral-400\">\n {isPlaying ? formatTime(currentTime) : formatTime(displayDuration)}\n </span>\n )}\n </div>\n );\n }\n\n // ============================================================================\n // Compact Variant\n // ============================================================================\n if (variant === 'compact') {\n return (\n <div className={cn(audioPlayerVariants({ variant, size }), className)}>\n {renderPlayButton()}\n <ProgressBar\n currentTime={currentTime}\n duration={duration}\n onSeek={handleSeek}\n disabled={disabled}\n />\n {renderTime()}\n {renderPlaybackRateControl()}\n </div>\n );\n }\n\n // ============================================================================\n // Waveform Variant\n // ============================================================================\n return (\n <div className={cn(audioPlayerVariants({ variant, size }), className)}>\n {title && (\n <span className=\"text-sm font-medium text-neutral-700 dark:text-neutral-300\">\n {title}\n </span>\n )}\n <Waveform\n src={src}\n isPlaying={isPlaying}\n playbackRate={playbackRate}\n onReady={handleWaveformReady}\n onTimeUpdate={handleWaveformTimeUpdate}\n onFinish={handleWaveformFinish}\n onSeek={handleWaveformSeek}\n waveColor={waveColor}\n progressColor={progressColor}\n height={waveformHeight}\n showHoverCursor={showWaveformHoverCursor}\n onHoverTimeChange={handleHoverTimeChange}\n cursorColor={waveformCursorColor}\n />\n <div className=\"flex items-center gap-3\">\n {renderPlayButton()}\n <div className=\"flex flex-1 items-center justify-between\">\n {renderTime(true)}\n {renderPlaybackRateControl()}\n </div>\n </div>\n </div>\n );\n}\n\nAudioPlayer.displayName = 'AudioPlayer';\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport { AudioPlayer, audioPlayerVariants, playButtonVariants, ProgressBar };\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-V2DF2GUE.js.map
3
+ //# sourceMappingURL=chunk-V2DF2GUE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-ZQ4XMJH7.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-V2DF2GUE.js"}
@@ -0,0 +1,9 @@
1
+ // src/utils/environment.ts
2
+ function isStorybookDocsMode() {
3
+ if (typeof window === "undefined") return false;
4
+ return window.location.search.includes("viewMode=docs");
5
+ }
6
+
7
+ export { isStorybookDocsMode };
8
+ //# sourceMappingURL=chunk-VSQF22GL.js.map
9
+ //# sourceMappingURL=chunk-VSQF22GL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/environment.ts"],"names":[],"mappings":";AAYO,SAAS,mBAAA,GAA+B;AAC7C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,KAAA;AAE1C,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,QAAA,CAAS,eAAe,CAAA;AACxD","file":"chunk-VSQF22GL.js","sourcesContent":["/**\n * Environment detection utilities for handling special rendering contexts\n * like Storybook, testing environments, etc.\n */\n\n/**\n * Check if we're in Storybook docs mode (multiple stories rendered inline).\n * In docs mode, we need to disable certain behaviors like scroll locking\n * and focus trapping that would interfere with the documentation page.\n *\n * @returns true if running in Storybook docs mode\n */\nexport function isStorybookDocsMode(): boolean {\n if (typeof window === 'undefined') return false;\n // Storybook docs mode renders in an iframe with viewMode=docs in the URL\n return window.location.search.includes('viewMode=docs');\n}\n"]}