@wow-two-beta/ui 0.0.20 → 0.0.21

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.
@@ -4,9 +4,9 @@ import { Icon } from './chunk-TDX22OWF.js';
4
4
  import { Slot, RovingFocusGroup, useRovingFocusItem, Portal, AnchoredPositioner } from './chunk-NC2CBGX2.js';
5
5
  import { composeRefs } from './chunk-DN7WBRIV.js';
6
6
  import { cn } from './chunk-KZ4VFY2T.js';
7
- import { forwardRef, useState, Children, isValidElement, Fragment as Fragment$1, createContext, useId, useMemo, useCallback, useContext, useEffect, useRef, cloneElement } from 'react';
7
+ import { forwardRef, useState, Children, isValidElement, Fragment as Fragment$1, createContext, useId, useMemo, useCallback, useContext, useEffect, useRef, useImperativeHandle, cloneElement } from 'react';
8
8
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
9
- import { TrendingUp, TrendingDown, Check, Copy, ChevronDown, ChevronLeft, ChevronRight, Plus, Minus, Maximize, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react';
9
+ import { TrendingUp, TrendingDown, Check, Copy, ChevronDown, ChevronLeft, ChevronRight, Plus, Minus, Maximize, Pause, Play, VolumeX, Volume2, Captions, CaptionsOff, PictureInPicture2, Minimize, ZoomOut, ZoomIn, Download, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react';
10
10
 
11
11
  // src/display/heading/Heading.variants.ts
12
12
  var headingVariants = tv({
@@ -2828,7 +2828,767 @@ var NodeEditor = forwardRef(function NodeEditor2({
2828
2828
  }
2829
2829
  );
2830
2830
  });
2831
+ var TONE_CLASS2 = {
2832
+ brand: "text-primary",
2833
+ success: "text-success",
2834
+ warning: "text-warning",
2835
+ danger: "text-destructive",
2836
+ muted: "text-muted-foreground",
2837
+ current: ""
2838
+ };
2839
+ var AudioWaveform = forwardRef(
2840
+ function AudioWaveform2({
2841
+ peaks,
2842
+ progress = 0,
2843
+ width = 320,
2844
+ height = 48,
2845
+ barWidth = 2,
2846
+ gap = 1,
2847
+ tone = "brand",
2848
+ onSeek,
2849
+ interactive,
2850
+ className,
2851
+ ...rest
2852
+ }, ref) {
2853
+ const stepX = barWidth + gap;
2854
+ const barCount = Math.max(1, Math.floor(width / stepX));
2855
+ const sampled = useMemo(() => sampleTo(peaks, barCount), [peaks, barCount]);
2856
+ const playedBars = Math.round(progress * barCount);
2857
+ const isInteractive = interactive ?? onSeek != null;
2858
+ const seekFromX = (clientX, rect) => {
2859
+ const x = Math.max(0, Math.min(rect.width, clientX - rect.left));
2860
+ onSeek?.(x / rect.width);
2861
+ };
2862
+ const svgRef = useRef(null);
2863
+ const handleKey = (e) => {
2864
+ if (!onSeek) return;
2865
+ if (e.key === "ArrowRight") {
2866
+ e.preventDefault();
2867
+ onSeek(Math.min(1, progress + 0.05));
2868
+ } else if (e.key === "ArrowLeft") {
2869
+ e.preventDefault();
2870
+ onSeek(Math.max(0, progress - 0.05));
2871
+ } else if (e.key === "Home") {
2872
+ e.preventDefault();
2873
+ onSeek(0);
2874
+ } else if (e.key === "End") {
2875
+ e.preventDefault();
2876
+ onSeek(1);
2877
+ }
2878
+ };
2879
+ return /* @__PURE__ */ jsx(
2880
+ "svg",
2881
+ {
2882
+ ref: (el) => {
2883
+ svgRef.current = el;
2884
+ if (typeof ref === "function") ref(el);
2885
+ else if (ref) ref.current = el;
2886
+ },
2887
+ role: isInteractive ? "slider" : "img",
2888
+ "aria-label": "Audio waveform",
2889
+ "aria-valuenow": Math.round(progress * 100),
2890
+ "aria-valuemin": 0,
2891
+ "aria-valuemax": 100,
2892
+ tabIndex: isInteractive ? 0 : -1,
2893
+ width,
2894
+ height,
2895
+ viewBox: `0 0 ${width} ${height}`,
2896
+ preserveAspectRatio: "none",
2897
+ onClick: isInteractive ? (e) => {
2898
+ const rect = svgRef.current?.getBoundingClientRect();
2899
+ if (rect) seekFromX(e.clientX, rect);
2900
+ } : void 0,
2901
+ onKeyDown: handleKey,
2902
+ className: cn(
2903
+ "inline-block",
2904
+ isInteractive && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm",
2905
+ TONE_CLASS2[tone],
2906
+ className
2907
+ ),
2908
+ ...rest,
2909
+ children: sampled.map((amp, i) => {
2910
+ const h = Math.max(1, amp * height);
2911
+ const x = i * stepX;
2912
+ const y = (height - h) / 2;
2913
+ const played = i < playedBars;
2914
+ return /* @__PURE__ */ jsx(
2915
+ "rect",
2916
+ {
2917
+ x,
2918
+ y,
2919
+ width: barWidth,
2920
+ height: h,
2921
+ rx: 1,
2922
+ className: played ? "fill-current" : "fill-current opacity-30"
2923
+ },
2924
+ i
2925
+ );
2926
+ })
2927
+ }
2928
+ );
2929
+ }
2930
+ );
2931
+ function sampleTo(peaks, n) {
2932
+ if (peaks.length === 0) return new Array(n).fill(0);
2933
+ if (peaks.length === n) return peaks;
2934
+ const out = new Array(n);
2935
+ const ratio = peaks.length / n;
2936
+ for (let i = 0; i < n; i++) {
2937
+ const start = Math.floor(i * ratio);
2938
+ const end = Math.max(start + 1, Math.floor((i + 1) * ratio));
2939
+ let max = 0;
2940
+ for (let j = start; j < end && j < peaks.length; j++) {
2941
+ const v = Math.abs(peaks[j]);
2942
+ if (v > max) max = v;
2943
+ }
2944
+ out[i] = max;
2945
+ }
2946
+ return out;
2947
+ }
2948
+ var SPEEDS = [0.5, 0.75, 1, 1.25, 1.5, 2];
2949
+ function formatTime(s) {
2950
+ if (!Number.isFinite(s) || s < 0) return "0:00";
2951
+ const total = Math.floor(s);
2952
+ const h = Math.floor(total / 3600);
2953
+ const m = Math.floor(total % 3600 / 60);
2954
+ const sec = total % 60;
2955
+ if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
2956
+ return `${m}:${String(sec).padStart(2, "0")}`;
2957
+ }
2958
+ var AudioPlayer = forwardRef(
2959
+ function AudioPlayer2({
2960
+ src,
2961
+ peaks,
2962
+ autoPlay,
2963
+ loop,
2964
+ defaultVolume = 1,
2965
+ defaultPlaybackRate = 1,
2966
+ compact,
2967
+ onPlay,
2968
+ onPause,
2969
+ onTimeUpdate,
2970
+ onEnded,
2971
+ className,
2972
+ ...rest
2973
+ }, forwardedRef) {
2974
+ const audioRef = useRef(null);
2975
+ useImperativeHandle(forwardedRef, () => audioRef.current);
2976
+ const [playing, setPlaying] = useState(!!autoPlay);
2977
+ const [currentTime, setCurrentTime] = useState(0);
2978
+ const [duration, setDuration] = useState(0);
2979
+ const [volume, setVolume] = useState(defaultVolume);
2980
+ const [muted, setMuted] = useState(false);
2981
+ const [speed, setSpeed] = useState(defaultPlaybackRate);
2982
+ useEffect(() => {
2983
+ const a = audioRef.current;
2984
+ if (!a) return;
2985
+ a.volume = volume;
2986
+ a.muted = muted;
2987
+ a.playbackRate = speed;
2988
+ }, [volume, muted, speed]);
2989
+ const togglePlay = useCallback(() => {
2990
+ const a = audioRef.current;
2991
+ if (!a) return;
2992
+ if (a.paused) {
2993
+ a.play().catch(() => {
2994
+ });
2995
+ } else {
2996
+ a.pause();
2997
+ }
2998
+ }, []);
2999
+ const seekTo = useCallback((seconds) => {
3000
+ const a = audioRef.current;
3001
+ if (!a || !Number.isFinite(seconds)) return;
3002
+ a.currentTime = Math.max(0, Math.min(a.duration || 0, seconds));
3003
+ }, []);
3004
+ const seekProgress = useCallback(
3005
+ (p) => {
3006
+ if (duration > 0) seekTo(p * duration);
3007
+ },
3008
+ [duration, seekTo]
3009
+ );
3010
+ const handleKey = (e) => {
3011
+ switch (e.key) {
3012
+ case " ":
3013
+ case "Spacebar":
3014
+ e.preventDefault();
3015
+ togglePlay();
3016
+ break;
3017
+ case "ArrowRight":
3018
+ e.preventDefault();
3019
+ seekTo(currentTime + 5);
3020
+ break;
3021
+ case "ArrowLeft":
3022
+ e.preventDefault();
3023
+ seekTo(currentTime - 5);
3024
+ break;
3025
+ case "ArrowUp":
3026
+ e.preventDefault();
3027
+ setVolume((v) => Math.min(1, v + 0.1));
3028
+ break;
3029
+ case "ArrowDown":
3030
+ e.preventDefault();
3031
+ setVolume((v) => Math.max(0, v - 0.1));
3032
+ break;
3033
+ case "m":
3034
+ case "M":
3035
+ e.preventDefault();
3036
+ setMuted((m) => !m);
3037
+ break;
3038
+ }
3039
+ };
3040
+ const progress = duration > 0 ? currentTime / duration : 0;
3041
+ return /* @__PURE__ */ jsxs(
3042
+ "div",
3043
+ {
3044
+ role: "region",
3045
+ "aria-label": "Audio player",
3046
+ tabIndex: 0,
3047
+ onKeyDown: handleKey,
3048
+ "data-playing": playing || void 0,
3049
+ className: cn(
3050
+ "flex items-center gap-3 rounded-md border border-border bg-card p-2 text-card-foreground shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3051
+ compact && "gap-2 p-1.5",
3052
+ className
3053
+ ),
3054
+ children: [
3055
+ /* @__PURE__ */ jsx(
3056
+ "audio",
3057
+ {
3058
+ ref: audioRef,
3059
+ src,
3060
+ autoPlay,
3061
+ loop,
3062
+ onPlay: () => {
3063
+ setPlaying(true);
3064
+ onPlay?.();
3065
+ },
3066
+ onPause: () => {
3067
+ setPlaying(false);
3068
+ onPause?.();
3069
+ },
3070
+ onTimeUpdate: () => {
3071
+ const a = audioRef.current;
3072
+ if (!a) return;
3073
+ setCurrentTime(a.currentTime);
3074
+ onTimeUpdate?.(a.currentTime, a.duration);
3075
+ },
3076
+ onLoadedMetadata: () => {
3077
+ const a = audioRef.current;
3078
+ if (a) setDuration(a.duration || 0);
3079
+ },
3080
+ onEnded: () => {
3081
+ setPlaying(false);
3082
+ onEnded?.();
3083
+ },
3084
+ ...rest
3085
+ }
3086
+ ),
3087
+ /* @__PURE__ */ jsx(
3088
+ "button",
3089
+ {
3090
+ type: "button",
3091
+ "aria-label": playing ? "Pause" : "Play",
3092
+ onClick: togglePlay,
3093
+ className: cn(
3094
+ "inline-flex shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3095
+ compact ? "h-7 w-7" : "h-9 w-9"
3096
+ ),
3097
+ children: /* @__PURE__ */ jsx(Icon, { icon: playing ? Pause : Play, size: compact ? 12 : 14 })
3098
+ }
3099
+ ),
3100
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", style: { minWidth: "3.5rem" }, children: formatTime(currentTime) }),
3101
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: peaks ? /* @__PURE__ */ jsx(
3102
+ AudioWaveform,
3103
+ {
3104
+ peaks,
3105
+ progress,
3106
+ onSeek: seekProgress,
3107
+ width: compact ? 200 : 320,
3108
+ height: compact ? 32 : 40
3109
+ }
3110
+ ) : /* @__PURE__ */ jsx(
3111
+ "input",
3112
+ {
3113
+ type: "range",
3114
+ role: "slider",
3115
+ "aria-label": "Seek",
3116
+ "aria-valuetext": formatTime(currentTime),
3117
+ min: 0,
3118
+ max: duration || 0,
3119
+ step: "any",
3120
+ value: currentTime,
3121
+ onChange: (e) => seekTo(Number(e.target.value)),
3122
+ className: "w-full accent-primary"
3123
+ }
3124
+ ) }),
3125
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", style: { minWidth: "3.5rem", textAlign: "right" }, children: formatTime(duration) }),
3126
+ /* @__PURE__ */ jsx(
3127
+ "button",
3128
+ {
3129
+ type: "button",
3130
+ "aria-label": muted ? "Unmute" : "Mute",
3131
+ onClick: () => setMuted((m) => !m),
3132
+ className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
3133
+ children: /* @__PURE__ */ jsx(Icon, { icon: muted || volume === 0 ? VolumeX : Volume2, size: 14 })
3134
+ }
3135
+ ),
3136
+ /* @__PURE__ */ jsx(
3137
+ "select",
3138
+ {
3139
+ "aria-label": "Playback speed",
3140
+ value: speed,
3141
+ onChange: (e) => setSpeed(Number(e.target.value)),
3142
+ className: "h-7 rounded-sm border border-input bg-background px-1 text-xs",
3143
+ children: SPEEDS.map((s) => /* @__PURE__ */ jsxs("option", { value: s, children: [
3144
+ s,
3145
+ "\xD7"
3146
+ ] }, s))
3147
+ }
3148
+ )
3149
+ ]
3150
+ }
3151
+ );
3152
+ }
3153
+ );
3154
+ var SPEEDS2 = [0.5, 0.75, 1, 1.25, 1.5, 2];
3155
+ function formatTime2(s) {
3156
+ if (!Number.isFinite(s) || s < 0) return "0:00";
3157
+ const total = Math.floor(s);
3158
+ const h = Math.floor(total / 3600);
3159
+ const m = Math.floor(total % 3600 / 60);
3160
+ const sec = total % 60;
3161
+ if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
3162
+ return `${m}:${String(sec).padStart(2, "0")}`;
3163
+ }
3164
+ var VideoPlayer = forwardRef(
3165
+ function VideoPlayer2({
3166
+ src,
3167
+ poster,
3168
+ tracks,
3169
+ aspectRatio = "16 / 9",
3170
+ autoPlay,
3171
+ loop,
3172
+ muted: mutedProp,
3173
+ defaultVolume = 1,
3174
+ defaultPlaybackRate = 1,
3175
+ className,
3176
+ ...rest
3177
+ }, forwardedRef) {
3178
+ const containerRef = useRef(null);
3179
+ const videoRef = useRef(null);
3180
+ useImperativeHandle(forwardedRef, () => videoRef.current);
3181
+ const [playing, setPlaying] = useState(!!autoPlay);
3182
+ const [currentTime, setCurrentTime] = useState(0);
3183
+ const [duration, setDuration] = useState(0);
3184
+ const [volume, setVolume] = useState(defaultVolume);
3185
+ const [muted, setMuted] = useState(!!mutedProp);
3186
+ const [speed, setSpeed] = useState(defaultPlaybackRate);
3187
+ const [fullscreen, setFullscreen] = useState(false);
3188
+ const [captionsOn, setCaptionsOn] = useState(false);
3189
+ const [showControls, setShowControls] = useState(true);
3190
+ const idleTimerRef = useRef(null);
3191
+ useEffect(() => {
3192
+ const v = videoRef.current;
3193
+ if (!v) return;
3194
+ v.volume = volume;
3195
+ v.muted = muted;
3196
+ v.playbackRate = speed;
3197
+ }, [volume, muted, speed]);
3198
+ useEffect(() => {
3199
+ const v = videoRef.current;
3200
+ if (!v || !v.textTracks) return;
3201
+ for (let i = 0; i < v.textTracks.length; i++) {
3202
+ v.textTracks[i].mode = captionsOn ? "showing" : "hidden";
3203
+ }
3204
+ }, [captionsOn, tracks]);
3205
+ useEffect(() => {
3206
+ const onFsChange = () => setFullscreen(document.fullscreenElement === containerRef.current);
3207
+ document.addEventListener("fullscreenchange", onFsChange);
3208
+ return () => document.removeEventListener("fullscreenchange", onFsChange);
3209
+ }, []);
3210
+ const togglePlay = useCallback(() => {
3211
+ const v = videoRef.current;
3212
+ if (!v) return;
3213
+ if (v.paused) v.play().catch(() => {
3214
+ });
3215
+ else v.pause();
3216
+ }, []);
3217
+ const seekTo = useCallback((seconds) => {
3218
+ const v = videoRef.current;
3219
+ if (!v || !Number.isFinite(seconds)) return;
3220
+ v.currentTime = Math.max(0, Math.min(v.duration || 0, seconds));
3221
+ }, []);
3222
+ const toggleFullscreen = useCallback(async () => {
3223
+ const c = containerRef.current;
3224
+ if (!c) return;
3225
+ if (!document.fullscreenElement) {
3226
+ await c.requestFullscreen?.().catch(() => {
3227
+ });
3228
+ } else {
3229
+ await document.exitFullscreen?.().catch(() => {
3230
+ });
3231
+ }
3232
+ }, []);
3233
+ const togglePiP = useCallback(async () => {
3234
+ const v = videoRef.current;
3235
+ if (!v) return;
3236
+ if ("pictureInPictureElement" in document && document.pictureInPictureElement) {
3237
+ await document.exitPictureInPicture?.()?.catch(() => {
3238
+ });
3239
+ } else if ("requestPictureInPicture" in v) {
3240
+ await v.requestPictureInPicture?.()?.catch(() => {
3241
+ });
3242
+ }
3243
+ }, []);
3244
+ const bumpControls = useCallback(() => {
3245
+ setShowControls(true);
3246
+ if (idleTimerRef.current != null) window.clearTimeout(idleTimerRef.current);
3247
+ if (playing) {
3248
+ idleTimerRef.current = window.setTimeout(() => setShowControls(false), 3e3);
3249
+ }
3250
+ }, [playing]);
3251
+ useEffect(() => {
3252
+ bumpControls();
3253
+ return () => {
3254
+ if (idleTimerRef.current != null) window.clearTimeout(idleTimerRef.current);
3255
+ };
3256
+ }, [playing, bumpControls]);
3257
+ const handleKey = (e) => {
3258
+ switch (e.key) {
3259
+ case " ":
3260
+ case "Spacebar":
3261
+ e.preventDefault();
3262
+ togglePlay();
3263
+ break;
3264
+ case "ArrowRight":
3265
+ e.preventDefault();
3266
+ seekTo(currentTime + 5);
3267
+ break;
3268
+ case "ArrowLeft":
3269
+ e.preventDefault();
3270
+ seekTo(currentTime - 5);
3271
+ break;
3272
+ case "ArrowUp":
3273
+ e.preventDefault();
3274
+ setVolume((v) => Math.min(1, v + 0.1));
3275
+ break;
3276
+ case "ArrowDown":
3277
+ e.preventDefault();
3278
+ setVolume((v) => Math.max(0, v - 0.1));
3279
+ break;
3280
+ case "m":
3281
+ case "M":
3282
+ e.preventDefault();
3283
+ setMuted((m) => !m);
3284
+ break;
3285
+ case "f":
3286
+ case "F":
3287
+ e.preventDefault();
3288
+ toggleFullscreen();
3289
+ break;
3290
+ case "c":
3291
+ case "C":
3292
+ e.preventDefault();
3293
+ if (tracks && tracks.length > 0) setCaptionsOn((c) => !c);
3294
+ break;
3295
+ }
3296
+ };
3297
+ return /* @__PURE__ */ jsxs(
3298
+ "div",
3299
+ {
3300
+ ref: containerRef,
3301
+ role: "region",
3302
+ "aria-label": "Video player",
3303
+ tabIndex: 0,
3304
+ onKeyDown: handleKey,
3305
+ onMouseMove: bumpControls,
3306
+ onMouseLeave: () => {
3307
+ if (playing) setShowControls(false);
3308
+ },
3309
+ className: cn(
3310
+ "group relative overflow-hidden rounded-md bg-black text-white shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3311
+ className
3312
+ ),
3313
+ style: { aspectRatio: typeof aspectRatio === "number" ? String(aspectRatio) : aspectRatio },
3314
+ children: [
3315
+ /* @__PURE__ */ jsx(
3316
+ "video",
3317
+ {
3318
+ ref: videoRef,
3319
+ src,
3320
+ poster,
3321
+ autoPlay,
3322
+ loop,
3323
+ muted,
3324
+ onPlay: () => setPlaying(true),
3325
+ onPause: () => setPlaying(false),
3326
+ onTimeUpdate: () => {
3327
+ const v = videoRef.current;
3328
+ if (!v) return;
3329
+ setCurrentTime(v.currentTime);
3330
+ },
3331
+ onLoadedMetadata: () => {
3332
+ const v = videoRef.current;
3333
+ if (v) setDuration(v.duration || 0);
3334
+ },
3335
+ onClick: togglePlay,
3336
+ className: "h-full w-full bg-black",
3337
+ ...rest,
3338
+ children: tracks?.map((t, i) => /* @__PURE__ */ jsx(
3339
+ "track",
3340
+ {
3341
+ src: t.src,
3342
+ srcLang: t.srcLang,
3343
+ label: t.label,
3344
+ kind: t.kind ?? "captions",
3345
+ default: t.default
3346
+ },
3347
+ i
3348
+ ))
3349
+ }
3350
+ ),
3351
+ !playing && /* @__PURE__ */ jsx(
3352
+ "button",
3353
+ {
3354
+ type: "button",
3355
+ "aria-label": "Play",
3356
+ onClick: togglePlay,
3357
+ className: "absolute inset-0 grid place-items-center bg-black/30 transition-opacity hover:bg-black/40",
3358
+ children: /* @__PURE__ */ jsx("span", { className: "grid h-16 w-16 place-items-center rounded-full bg-white/90 text-foreground shadow-lg", children: /* @__PURE__ */ jsx(Icon, { icon: Play, size: 28 }) })
3359
+ }
3360
+ ),
3361
+ /* @__PURE__ */ jsxs(
3362
+ "div",
3363
+ {
3364
+ className: cn(
3365
+ "absolute inset-x-0 bottom-0 flex items-center gap-2 bg-gradient-to-t from-black/80 to-transparent px-3 pb-2 pt-6 transition-opacity",
3366
+ showControls ? "opacity-100" : "opacity-0"
3367
+ ),
3368
+ children: [
3369
+ /* @__PURE__ */ jsx(
3370
+ "button",
3371
+ {
3372
+ type: "button",
3373
+ "aria-label": playing ? "Pause" : "Play",
3374
+ onClick: togglePlay,
3375
+ className: "inline-flex h-8 w-8 items-center justify-center rounded-full bg-white/20 text-white hover:bg-white/30",
3376
+ children: /* @__PURE__ */ jsx(Icon, { icon: playing ? Pause : Play, size: 14 })
3377
+ }
3378
+ ),
3379
+ /* @__PURE__ */ jsxs("span", { className: "text-xs tabular-nums", children: [
3380
+ formatTime2(currentTime),
3381
+ " / ",
3382
+ formatTime2(duration)
3383
+ ] }),
3384
+ /* @__PURE__ */ jsx(
3385
+ "input",
3386
+ {
3387
+ type: "range",
3388
+ role: "slider",
3389
+ "aria-label": "Seek",
3390
+ "aria-valuetext": formatTime2(currentTime),
3391
+ min: 0,
3392
+ max: duration || 0,
3393
+ step: "any",
3394
+ value: currentTime,
3395
+ onChange: (e) => seekTo(Number(e.target.value)),
3396
+ className: "flex-1 accent-primary"
3397
+ }
3398
+ ),
3399
+ /* @__PURE__ */ jsx(
3400
+ "button",
3401
+ {
3402
+ type: "button",
3403
+ "aria-label": muted || volume === 0 ? "Unmute" : "Mute",
3404
+ onClick: () => setMuted((m) => !m),
3405
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-white/80 hover:bg-white/20 hover:text-white",
3406
+ children: /* @__PURE__ */ jsx(Icon, { icon: muted || volume === 0 ? VolumeX : Volume2, size: 14 })
3407
+ }
3408
+ ),
3409
+ /* @__PURE__ */ jsx(
3410
+ "select",
3411
+ {
3412
+ "aria-label": "Playback speed",
3413
+ value: speed,
3414
+ onChange: (e) => setSpeed(Number(e.target.value)),
3415
+ className: "h-7 rounded-sm border border-white/20 bg-black/40 px-1 text-xs",
3416
+ children: SPEEDS2.map((s) => /* @__PURE__ */ jsxs("option", { value: s, className: "text-foreground", children: [
3417
+ s,
3418
+ "\xD7"
3419
+ ] }, s))
3420
+ }
3421
+ ),
3422
+ tracks && tracks.length > 0 && /* @__PURE__ */ jsx(
3423
+ "button",
3424
+ {
3425
+ type: "button",
3426
+ "aria-label": captionsOn ? "Hide captions" : "Show captions",
3427
+ "aria-pressed": captionsOn,
3428
+ onClick: () => setCaptionsOn((c) => !c),
3429
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-white/80 hover:bg-white/20 hover:text-white",
3430
+ children: /* @__PURE__ */ jsx(Icon, { icon: captionsOn ? Captions : CaptionsOff, size: 14 })
3431
+ }
3432
+ ),
3433
+ /* @__PURE__ */ jsx(
3434
+ "button",
3435
+ {
3436
+ type: "button",
3437
+ "aria-label": "Picture in picture",
3438
+ onClick: togglePiP,
3439
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-white/80 hover:bg-white/20 hover:text-white",
3440
+ children: /* @__PURE__ */ jsx(Icon, { icon: PictureInPicture2, size: 14 })
3441
+ }
3442
+ ),
3443
+ /* @__PURE__ */ jsx(
3444
+ "button",
3445
+ {
3446
+ type: "button",
3447
+ "aria-label": fullscreen ? "Exit fullscreen" : "Enter fullscreen",
3448
+ onClick: toggleFullscreen,
3449
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-white/80 hover:bg-white/20 hover:text-white",
3450
+ children: /* @__PURE__ */ jsx(Icon, { icon: fullscreen ? Minimize : Maximize, size: 14 })
3451
+ }
3452
+ )
3453
+ ]
3454
+ }
3455
+ )
3456
+ ]
3457
+ }
3458
+ );
3459
+ }
3460
+ );
3461
+ var ZOOM_LEVELS = [50, 75, 100, 125, 150, 175, 200, 250, 300, 400];
3462
+ var PDFViewer = forwardRef(function PDFViewer2({
3463
+ src,
3464
+ page: pageProp,
3465
+ defaultPage = 1,
3466
+ onPageChange,
3467
+ zoom: zoomProp,
3468
+ defaultZoom = 100,
3469
+ onZoomChange,
3470
+ pageCount,
3471
+ title = "PDF document",
3472
+ download = true,
3473
+ height = "70vh",
3474
+ className,
3475
+ ...rest
3476
+ }, ref) {
3477
+ const [page, setPage] = useControlled({
3478
+ controlled: pageProp,
3479
+ default: defaultPage,
3480
+ onChange: onPageChange
3481
+ });
3482
+ const [zoom, setZoom] = useControlled({
3483
+ controlled: zoomProp,
3484
+ default: defaultZoom,
3485
+ onChange: onZoomChange
3486
+ });
3487
+ const hashedSrc = useMemo(() => {
3488
+ try {
3489
+ const url = new URL(src, typeof window !== "undefined" ? window.location.href : "http://localhost");
3490
+ url.hash = `page=${page}&zoom=${zoom}`;
3491
+ return url.toString();
3492
+ } catch {
3493
+ return `${src}#page=${page}&zoom=${zoom}`;
3494
+ }
3495
+ }, [src, page, zoom]);
3496
+ const goPrev = () => setPage(Math.max(1, page - 1));
3497
+ const goNext = () => setPage(pageCount ? Math.min(pageCount, page + 1) : page + 1);
3498
+ const zoomIn = () => {
3499
+ const next = ZOOM_LEVELS.find((z) => z > zoom);
3500
+ if (next) setZoom(next);
3501
+ };
3502
+ const zoomOut = () => {
3503
+ const next = [...ZOOM_LEVELS].reverse().find((z) => z < zoom);
3504
+ if (next) setZoom(next);
3505
+ };
3506
+ return /* @__PURE__ */ jsxs(
3507
+ "div",
3508
+ {
3509
+ ref,
3510
+ className: cn(
3511
+ "flex flex-col overflow-hidden rounded-md border border-border bg-card text-card-foreground shadow-sm",
3512
+ className
3513
+ ),
3514
+ ...rest,
3515
+ children: [
3516
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 border-b border-border bg-muted/40 px-2 py-1.5", children: [
3517
+ /* @__PURE__ */ jsx(
3518
+ "button",
3519
+ {
3520
+ type: "button",
3521
+ "aria-label": "Previous page",
3522
+ onClick: goPrev,
3523
+ disabled: page <= 1,
3524
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40",
3525
+ children: /* @__PURE__ */ jsx(Icon, { icon: ChevronLeft, size: 14 })
3526
+ }
3527
+ ),
3528
+ /* @__PURE__ */ jsx("span", { className: "px-1 text-xs tabular-nums text-foreground", children: pageCount ? `${page} / ${pageCount}` : `Page ${page}` }),
3529
+ /* @__PURE__ */ jsx(
3530
+ "button",
3531
+ {
3532
+ type: "button",
3533
+ "aria-label": "Next page",
3534
+ onClick: goNext,
3535
+ disabled: pageCount != null && page >= pageCount,
3536
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40",
3537
+ children: /* @__PURE__ */ jsx(Icon, { icon: ChevronRight, size: 14 })
3538
+ }
3539
+ ),
3540
+ /* @__PURE__ */ jsx("span", { className: "mx-2 h-4 w-px bg-border", "aria-hidden": "true" }),
3541
+ /* @__PURE__ */ jsx(
3542
+ "button",
3543
+ {
3544
+ type: "button",
3545
+ "aria-label": "Zoom out",
3546
+ onClick: zoomOut,
3547
+ disabled: zoom <= ZOOM_LEVELS[0],
3548
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40",
3549
+ children: /* @__PURE__ */ jsx(Icon, { icon: ZoomOut, size: 14 })
3550
+ }
3551
+ ),
3552
+ /* @__PURE__ */ jsxs("span", { className: "px-1 text-xs tabular-nums text-foreground", children: [
3553
+ zoom,
3554
+ "%"
3555
+ ] }),
3556
+ /* @__PURE__ */ jsx(
3557
+ "button",
3558
+ {
3559
+ type: "button",
3560
+ "aria-label": "Zoom in",
3561
+ onClick: zoomIn,
3562
+ disabled: zoom >= ZOOM_LEVELS[ZOOM_LEVELS.length - 1],
3563
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40",
3564
+ children: /* @__PURE__ */ jsx(Icon, { icon: ZoomIn, size: 14 })
3565
+ }
3566
+ ),
3567
+ /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-1", children: download && /* @__PURE__ */ jsx(
3568
+ "a",
3569
+ {
3570
+ href: src,
3571
+ download: true,
3572
+ "aria-label": "Download PDF",
3573
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
3574
+ children: /* @__PURE__ */ jsx(Icon, { icon: Download, size: 14 })
3575
+ }
3576
+ ) })
3577
+ ] }),
3578
+ /* @__PURE__ */ jsx(
3579
+ "iframe",
3580
+ {
3581
+ src: hashedSrc,
3582
+ title,
3583
+ style: { height, border: 0 },
3584
+ className: "w-full bg-muted"
3585
+ }
3586
+ )
3587
+ ]
3588
+ }
3589
+ );
3590
+ });
2831
3591
 
2832
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Avatar, AvatarGroup, Badge, BadgeOverlay, Card, Carousel, CarouselDot, CarouselDots, CarouselNext, CarouselPrev, CarouselSlide, CarouselSlides, CarouselViewport, Code, Collapsible, CollapsibleContent, CollapsibleTrigger, CountBadge, DataGrid, DataTable, DescriptionList, DiffViewer, EmptyState, Heading, HeatmapCalendar, Highlight, Image, InfoRow, Kbd, KeyboardShortcut, List, ListItem, Mark, NodeEditor, NotificationDot, Quote, SectionHeader, Separator, Snippet, Sparkline, Stat, Status, SwipeActions, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeaderCell, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Text, Timeline, TimelineDescription, TimelineItem, TimelineTitle, Tooltip, Tree, TreeGroup, TreeItem, avatarVariants, badgeVariants, codeVariants, headingVariants, textVariants };
2833
- //# sourceMappingURL=chunk-RK6VB3II.js.map
2834
- //# sourceMappingURL=chunk-RK6VB3II.js.map
3592
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AudioPlayer, AudioWaveform, Avatar, AvatarGroup, Badge, BadgeOverlay, Card, Carousel, CarouselDot, CarouselDots, CarouselNext, CarouselPrev, CarouselSlide, CarouselSlides, CarouselViewport, Code, Collapsible, CollapsibleContent, CollapsibleTrigger, CountBadge, DataGrid, DataTable, DescriptionList, DiffViewer, EmptyState, Heading, HeatmapCalendar, Highlight, Image, InfoRow, Kbd, KeyboardShortcut, List, ListItem, Mark, NodeEditor, NotificationDot, PDFViewer, Quote, SectionHeader, Separator, Snippet, Sparkline, Stat, Status, SwipeActions, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeaderCell, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Text, Timeline, TimelineDescription, TimelineItem, TimelineTitle, Tooltip, Tree, TreeGroup, TreeItem, VideoPlayer, avatarVariants, badgeVariants, codeVariants, headingVariants, textVariants };
3593
+ //# sourceMappingURL=chunk-CBOC2DT2.js.map
3594
+ //# sourceMappingURL=chunk-CBOC2DT2.js.map