@mieweb/ui 0.11.0-dev.53 → 0.11.0-dev.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -117,7 +117,7 @@ var chunkHDZQLTBP_cjs = require('./chunk-HDZQLTBP.cjs');
117
117
  var chunk7WJ6MBF5_cjs = require('./chunk-7WJ6MBF5.cjs');
118
118
  require('./chunk-AT732HC6.cjs');
119
119
  var chunkL7YQBSEL_cjs = require('./chunk-L7YQBSEL.cjs');
120
- var chunkXWGPEIVB_cjs = require('./chunk-XWGPEIVB.cjs');
120
+ var chunk2UGMTGH2_cjs = require('./chunk-2UGMTGH2.cjs');
121
121
  var chunkPRGQVUMU_cjs = require('./chunk-PRGQVUMU.cjs');
122
122
  require('./chunk-P22YCUVM.cjs');
123
123
  var chunkQ3YVLO52_cjs = require('./chunk-Q3YVLO52.cjs');
@@ -3723,18 +3723,10 @@ function overlappingLanes({ probabilities, numSpeakers }, [from, to], primary) {
3723
3723
  }
3724
3724
  return lanes;
3725
3725
  }
3726
- function transcriptFromFrames(words, frames, names, durationSeconds) {
3727
- const ids = names.map((_, lane) => `lane-${lane}`);
3726
+ function buildTranscript(words, attribute, { durationMs, speakers, speakerActivity }) {
3728
3727
  const segments = [];
3729
3728
  for (const word of words) {
3730
- const range = wordFrameRange(frames, word);
3731
- const means = laneMeans(frames, range);
3732
- let lane = 0;
3733
- for (let l = 1; l < means.length; l++) if (means[l] > means[lane]) lane = l;
3734
- const speakerId = ids[lane] ?? `lane-${lane}`;
3735
- const others = overlappingLanes(frames, range, lane).map(
3736
- (l) => ids[l] ?? `lane-${l}`
3737
- );
3729
+ const { speakerId, others } = attribute(word);
3738
3730
  const spoken = {
3739
3731
  text: word.text.trim(),
3740
3732
  startMs: ms(word.start),
@@ -3758,19 +3750,104 @@ function transcriptFromFrames(words, frames, names, durationSeconds) {
3758
3750
  ...others.length ? { overlapSpeakerIds: others } : {}
3759
3751
  });
3760
3752
  }
3761
- const speakerActivity = laneActivity(frames);
3762
3753
  const heard = /* @__PURE__ */ new Set([
3763
3754
  ...segments.map((s) => s.speakerId),
3764
3755
  ...speakerActivity.map((a) => a.speakerId)
3765
3756
  ]);
3766
3757
  return {
3767
- durationMs: ms(durationSeconds),
3768
- speakers: names.map((name, lane) => ({ id: ids[lane], name })).filter((s) => heard.has(s.id)),
3758
+ durationMs,
3759
+ speakers: speakers.filter((s) => heard.has(s.id)),
3769
3760
  segments,
3770
3761
  words: segments.flatMap((s) => s.words),
3771
3762
  speakerActivity
3772
3763
  };
3773
3764
  }
3765
+ var laneSpeakers = (names) => names.map((name, lane) => ({ id: `lane-${lane}`, name }));
3766
+ function timelineFromFrames(frames, names, durationSeconds) {
3767
+ const speakerActivity = laneActivity(frames);
3768
+ const heard = new Set(speakerActivity.map((a) => a.speakerId));
3769
+ return {
3770
+ durationMs: ms(durationSeconds),
3771
+ speakers: laneSpeakers(names).filter((s) => heard.has(s.id)),
3772
+ speakerActivity
3773
+ };
3774
+ }
3775
+ function transcriptFromFrames(words, frames, names, durationSeconds) {
3776
+ const id = (lane) => `lane-${lane}`;
3777
+ return buildTranscript(
3778
+ words,
3779
+ (word) => {
3780
+ const range = wordFrameRange(frames, word);
3781
+ const means = laneMeans(frames, range);
3782
+ let lane = 0;
3783
+ for (let l = 1; l < means.length; l++)
3784
+ if (means[l] > means[lane]) lane = l;
3785
+ return {
3786
+ speakerId: id(lane),
3787
+ others: overlappingLanes(frames, range, lane).map(id)
3788
+ };
3789
+ },
3790
+ // Every named lane: a word can land on a lane with no activity of its own.
3791
+ {
3792
+ ...timelineFromFrames(frames, names, durationSeconds),
3793
+ speakers: laneSpeakers(names)
3794
+ }
3795
+ );
3796
+ }
3797
+ function transcriptFromActivity(words, timeline) {
3798
+ const spans = timeline.speakerActivity;
3799
+ const speakers = timeline.speakers.length ? timeline.speakers : [{ id: "lane-0", name: "Speaker 1" }];
3800
+ const fallback = speakers[0].id;
3801
+ return buildTranscript(
3802
+ words,
3803
+ (word) => {
3804
+ const from = ms(word.start);
3805
+ const to = Math.max(ms(word.end), from + 1);
3806
+ const heard = spans.filter((s) => s.startMs < to && s.endMs > from);
3807
+ if (heard.length === 0) {
3808
+ const gap = (s) => Math.max(s.startMs - to, from - s.endMs);
3809
+ const nearest = spans.reduce(
3810
+ (best, s) => !best || gap(s) < gap(best) ? s : best,
3811
+ void 0
3812
+ );
3813
+ return { speakerId: nearest?.speakerId ?? fallback, others: [] };
3814
+ }
3815
+ const within = (s) => [
3816
+ Math.max(from, s.startMs),
3817
+ Math.min(to, s.endMs)
3818
+ ];
3819
+ const totals = /* @__PURE__ */ new Map();
3820
+ for (const s of heard) {
3821
+ const [start, end] = within(s);
3822
+ totals.set(s.speakerId, (totals.get(s.speakerId) ?? 0) + end - start);
3823
+ }
3824
+ const rank = (id) => {
3825
+ const i = speakers.findIndex((s) => s.id === id);
3826
+ return i < 0 ? Infinity : i;
3827
+ };
3828
+ let speakerId = heard[0].speakerId;
3829
+ for (const [id, total] of totals) {
3830
+ const best = totals.get(speakerId) ?? 0;
3831
+ if (total > best || total === best && rank(id) < rank(speakerId))
3832
+ speakerId = id;
3833
+ }
3834
+ const mine = heard.filter((s) => s.speakerId === speakerId);
3835
+ const together = (s) => {
3836
+ const [start, end] = within(s);
3837
+ return mine.some(
3838
+ (m) => Math.min(end, m.endMs) > Math.max(start, m.startMs)
3839
+ );
3840
+ };
3841
+ const others = [
3842
+ ...new Set(
3843
+ heard.filter((s) => s.speakerId !== speakerId && together(s)).map((s) => s.speakerId)
3844
+ )
3845
+ ];
3846
+ return { speakerId, others };
3847
+ },
3848
+ { ...timeline, speakers }
3849
+ );
3850
+ }
3774
3851
 
3775
3852
  // src/components/AI/HeyOzwell/audio.ts
3776
3853
  function openRollingRecorder(stream, maxSeconds = 2) {
@@ -3984,6 +4061,7 @@ function listenNemotron(stream, options, onStage) {
3984
4061
  let cursor = 0;
3985
4062
  let pushed = Promise.resolve();
3986
4063
  let open = true;
4064
+ let paused = false;
3987
4065
  const close = () => {
3988
4066
  if (!open) return;
3989
4067
  open = false;
@@ -3995,7 +4073,7 @@ function listenNemotron(stream, options, onStage) {
3995
4073
  const fresh = recorder.snapshotFrom(cursor);
3996
4074
  cursor += fresh.length;
3997
4075
  recorder.discardBefore(cursor);
3998
- if (fresh.length > 0) {
4076
+ if (fresh.length > 0 && !paused) {
3999
4077
  const samples = chunkRDERYV5M_cjs.resampleTo16kMono(fresh, recorder.sampleRate);
4000
4078
  pushed = pushed.then(() => nemotron.push(samples));
4001
4079
  pushed.catch(() => {
@@ -4017,6 +4095,14 @@ function listenNemotron(stream, options, onStage) {
4017
4095
  void pushed.catch(() => {
4018
4096
  }).then(() => nemotron.finish()).catch(() => {
4019
4097
  });
4098
+ },
4099
+ pause: () => {
4100
+ drain();
4101
+ paused = true;
4102
+ },
4103
+ resume: () => {
4104
+ drain();
4105
+ paused = false;
4020
4106
  }
4021
4107
  };
4022
4108
  }
@@ -4248,7 +4334,9 @@ function useNemotronDiarization({
4248
4334
  names,
4249
4335
  namespace: nsRef.current,
4250
4336
  hydrated: hydratedRef.current,
4251
- cancel: listener.cancel
4337
+ cancel: listener.cancel,
4338
+ pause: listener.pause,
4339
+ resume: listener.resume
4252
4340
  };
4253
4341
  return session;
4254
4342
  },
@@ -4295,6 +4383,27 @@ function useNemotronDiarization({
4295
4383
  }),
4296
4384
  [track, labelSpeakers]
4297
4385
  );
4386
+ const finish = React16__namespace.useCallback(
4387
+ (live) => {
4388
+ const session = live;
4389
+ const stopping = session.namespace === nsRef.current ? session.listener.stop() : null;
4390
+ if (stopping) stopping.catch(() => {
4391
+ });
4392
+ else session.cancel();
4393
+ return track(async (assertNamespace) => {
4394
+ if (!stopping)
4395
+ throw new Error("Voiceprint namespace changed during processing");
4396
+ const frames = await stopping;
4397
+ assertNamespace();
4398
+ return timelineFromFrames(
4399
+ frames,
4400
+ laneNames(frames, session.names),
4401
+ frames.numFrames * frames.frameDurationSeconds
4402
+ );
4403
+ });
4404
+ },
4405
+ [track]
4406
+ );
4298
4407
  const voices = React16__namespace.useMemo(
4299
4408
  () => prints.map((p) => ({
4300
4409
  name: p.name,
@@ -4312,7 +4421,8 @@ function useNemotronDiarization({
4312
4421
  enroll,
4313
4422
  removeVoice,
4314
4423
  listen,
4315
- diarize
4424
+ diarize,
4425
+ finish
4316
4426
  };
4317
4427
  }
4318
4428
 
@@ -6811,6 +6921,8 @@ var DEFAULT_TRANSCRIPT_PLAYER_LABELS = {
6811
6921
  searchTranscript: "Search transcript",
6812
6922
  searchPlaceholder: "Search transcript\u2026",
6813
6923
  showSpeakers: "Show speakers",
6924
+ showSpeakerLanes: "Show speakers",
6925
+ hideSpeakerLanes: "Hide speakers",
6814
6926
  allSpeakers: "All speakers",
6815
6927
  someSpeakers: "Some speakers",
6816
6928
  noTranscript: "No transcript for this recording.",
@@ -6834,7 +6946,7 @@ var DEFAULT_TRANSCRIPT_PLAYER_LABELS = {
6834
6946
  seekValue: (current, total) => `${current} of ${total}`,
6835
6947
  windowValue: (start, end) => `${start} to ${end}`
6836
6948
  };
6837
- var ROW_GRID = "grid grid-cols-[6.5rem_minmax(0,1fr)] items-center gap-x-3";
6949
+ var ROW_GRID = "grid grid-cols-[var(--tp-label,6.5rem)_minmax(0,1fr)] items-center gap-x-3";
6838
6950
  var HIDE_DELAY_MS = 150;
6839
6951
  var viewFraction = (time, view) => view.span > 0 ? Math.min(1, Math.max(0, (time - view.start) / view.span)) : 0;
6840
6952
  var timeAtPointer = (clientX, element, view) => {
@@ -7231,10 +7343,13 @@ function TimelineOverview({
7231
7343
  {
7232
7344
  "aria-hidden": "true",
7233
7345
  className: "text-muted-foreground relative mx-9 mt-1 h-4 text-[11px] tabular-nums",
7234
- children: ticksFor(whole).map((t) => /* @__PURE__ */ jsxRuntime.jsx(
7346
+ children: ticksFor(whole).map((t, i) => /* @__PURE__ */ jsxRuntime.jsx(
7235
7347
  "span",
7236
7348
  {
7237
- className: "absolute -translate-x-1/2",
7349
+ className: chunkS5RVSXDV_cjs.cn(
7350
+ "absolute -translate-x-1/2",
7351
+ i % 2 === 1 && "hidden @md:inline"
7352
+ ),
7238
7353
  style: {
7239
7354
  // rtl-ignore -- time axis inside the player's dir="ltr" timeline
7240
7355
  left: `${viewFraction(t, whole) * 100}%`
@@ -7293,7 +7408,8 @@ var Row = React16__namespace.memo(function Row2({
7293
7408
  "aria-posinset": posInSet,
7294
7409
  onClick: () => onPlay(utterance),
7295
7410
  className: chunkS5RVSXDV_cjs.cn(
7296
- "flex cursor-pointer items-start gap-3 rounded-lg px-2 py-2 text-sm",
7411
+ // Narrow hosts put the text on its own line under the time and speaker.
7412
+ "flex cursor-pointer flex-wrap items-start gap-x-3 gap-y-1 rounded-lg px-2 py-2 text-sm @md:flex-nowrap",
7297
7413
  active ? "bg-primary-50 dark:bg-primary-950/40" : "hover:bg-muted/60"
7298
7414
  ),
7299
7415
  children: [
@@ -7335,7 +7451,7 @@ var Row = React16__namespace.memo(function Row2({
7335
7451
  ]
7336
7452
  }
7337
7453
  ),
7338
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
7454
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 grow basis-full ps-9 @md:basis-0 @md:ps-0", children: [
7339
7455
  utterance.text ? highlight(utterance.text, query) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground italic", children: labels.noWords }),
7340
7456
  overlap && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground border-border ms-2 inline-block max-w-full rounded border px-1.5 text-[11px] break-words", children: labels.overlapWith(overlap) })
7341
7457
  ] })
@@ -7423,7 +7539,7 @@ function TranscriptList({
7423
7539
  "p",
7424
7540
  {
7425
7541
  role: "status",
7426
- className: "text-muted-foreground flex h-80 items-center justify-center p-6 text-center text-sm",
7542
+ className: "text-muted-foreground flex items-center justify-center p-6 text-center text-sm",
7427
7543
  children: emptyMessage
7428
7544
  }
7429
7545
  );
@@ -7442,7 +7558,7 @@ function TranscriptList({
7442
7558
  if (e.target === e.currentTarget && USER_SCROLL_KEYS.has(e.key))
7443
7559
  setDetached(true);
7444
7560
  },
7445
- className: "focus-visible:ring-ring h-80 overflow-y-auto rounded-lg focus-visible:ring-2 focus-visible:outline-none",
7561
+ className: "focus-visible:ring-ring max-h-80 overflow-y-auto rounded-lg focus-visible:ring-2 focus-visible:outline-none",
7446
7562
  children: virtualize ? /* @__PURE__ */ jsxRuntime.jsx(
7447
7563
  "div",
7448
7564
  {
@@ -7688,7 +7804,7 @@ function inertOutside(element) {
7688
7804
  }
7689
7805
  return () => changed.forEach((el) => el.removeAttribute("inert"));
7690
7806
  }
7691
- var TRACK_OFFSET = "7.25rem";
7807
+ var TRACK_OFFSET = "calc(var(--tp-label, 6.5rem) + 0.75rem)";
7692
7808
  var pressedButton = "aria-pressed:bg-primary-50 aria-pressed:text-primary-800 dark:aria-pressed:bg-primary-950 dark:aria-pressed:text-primary-200";
7693
7809
  function TranscriptPlayer({
7694
7810
  src,
@@ -7696,11 +7812,17 @@ function TranscriptPlayer({
7696
7812
  speakerLabels,
7697
7813
  peaks: providedPeaks,
7698
7814
  labels: labelOverrides,
7815
+ collapsibleLanes = false,
7816
+ showSpeakerPanel = true,
7817
+ sticky = true,
7699
7818
  className
7700
7819
  }) {
7701
7820
  const rootRef = React16__namespace.useRef(null);
7702
7821
  const fullscreenButtonRef = React16__namespace.useRef(null);
7703
7822
  const transcriptHeadingId = React16__namespace.useId();
7823
+ const lanesId = React16__namespace.useId();
7824
+ const [lanesOpen, setLanesOpen] = React16__namespace.useState(!collapsibleLanes);
7825
+ const showLanes = !collapsibleLanes || lanesOpen;
7704
7826
  const labels = React16__namespace.useMemo(
7705
7827
  () => ({ ...DEFAULT_TRANSCRIPT_PLAYER_LABELS, ...labelOverrides }),
7706
7828
  [labelOverrides]
@@ -7782,7 +7904,10 @@ function TranscriptPlayer({
7782
7904
  const onKeyDown = (event) => {
7783
7905
  if (event.key !== "Escape" || document.fullscreenElement) return;
7784
7906
  const target = event.target;
7785
- if (target?.closest?.('[aria-expanded="true"]')) return;
7907
+ if (target?.closest?.(
7908
+ '[aria-expanded="true"][aria-haspopup]:not([aria-haspopup="false"])'
7909
+ ))
7910
+ return;
7786
7911
  if (target?.type === "search" && target.value) return;
7787
7912
  setFullscreen(false);
7788
7913
  };
@@ -7890,7 +8015,8 @@ function TranscriptPlayer({
7890
8015
  {
7891
8016
  ref: rootRef,
7892
8017
  className: chunkS5RVSXDV_cjs.cn(
7893
- "text-foreground flex flex-col gap-4",
8018
+ // Sized by its container, not the viewport, so it also fits narrow hosts such as a chat bubble.
8019
+ "text-foreground @container flex flex-col gap-4",
7894
8020
  fullscreen && "bg-background fixed inset-0 z-50 overflow-y-auto p-6",
7895
8021
  className
7896
8022
  ),
@@ -7909,9 +8035,13 @@ function TranscriptPlayer({
7909
8035
  "section",
7910
8036
  {
7911
8037
  "aria-label": labels.recording,
7912
- className: "border-border bg-card text-card-foreground sticky top-0 z-10 rounded-xl border p-4",
8038
+ className: chunkS5RVSXDV_cjs.cn(
8039
+ // The label width is set here, not on the root: a container query only sees an ancestor.
8040
+ "border-border bg-card text-card-foreground rounded-xl border p-3 [--tp-label:4.5rem] @md:p-4 @md:[--tp-label:6.5rem]",
8041
+ sticky && "sticky top-0 z-10"
8042
+ ),
7913
8043
  children: [
7914
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex flex-wrap items-center gap-x-4 gap-y-2", children: [
8044
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex flex-wrap items-center gap-x-4 gap-y-2", children: [
7915
8045
  /* @__PURE__ */ jsxRuntime.jsx(
7916
8046
  chunkFSARTLUE_cjs.Button,
7917
8047
  {
@@ -7941,7 +8071,23 @@ function TranscriptPlayer({
7941
8071
  ] }),
7942
8072
  playback.error && /* @__PURE__ */ jsxRuntime.jsx("span", { role: "alert", className: "text-destructive text-sm", children: playback.error === "load" ? labels.loadError : labels.playError }),
7943
8073
  !src && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm", children: labels.noRecording }),
7944
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ms-auto flex items-center gap-2", children: [
8074
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ms-auto flex flex-wrap items-center gap-2", children: [
8075
+ collapsibleLanes && /* @__PURE__ */ jsxRuntime.jsxs(
8076
+ chunkFSARTLUE_cjs.Button,
8077
+ {
8078
+ type: "button",
8079
+ variant: "ghost",
8080
+ size: "sm",
8081
+ "aria-expanded": lanesOpen,
8082
+ "aria-controls": lanesId,
8083
+ onClick: () => setLanesOpen((open) => !open),
8084
+ "aria-label": lanesOpen ? labels.hideSpeakerLanes : labels.showSpeakerLanes,
8085
+ children: [
8086
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { "aria-hidden": "true", className: "h-4 w-4 @sm:me-1.5" }),
8087
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "hidden @sm:inline", children: lanesOpen ? labels.hideSpeakerLanes : labels.showSpeakerLanes })
8088
+ ]
8089
+ }
8090
+ ),
7945
8091
  /* @__PURE__ */ jsxRuntime.jsx(
7946
8092
  chunkFSARTLUE_cjs.Button,
7947
8093
  {
@@ -7959,7 +8105,7 @@ function TranscriptPlayer({
7959
8105
  children: playback.volume === 0 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VolumeX, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Volume2, { "aria-hidden": "true", className: "h-4 w-4" })
7960
8106
  }
7961
8107
  ),
7962
- /* @__PURE__ */ jsxRuntime.jsx(
8108
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden @md:block", children: /* @__PURE__ */ jsxRuntime.jsx(
7963
8109
  chunkZDA6FEKA_cjs.Slider,
7964
8110
  {
7965
8111
  "aria-label": labels.volume,
@@ -7971,7 +8117,7 @@ function TranscriptPlayer({
7971
8117
  size: "sm",
7972
8118
  className: "w-24"
7973
8119
  }
7974
- ),
8120
+ ) }),
7975
8121
  /* @__PURE__ */ jsxRuntime.jsx(
7976
8122
  chunkUPWIJC6I_cjs.Select,
7977
8123
  {
@@ -8000,75 +8146,90 @@ function TranscriptPlayer({
8000
8146
  )
8001
8147
  ] })
8002
8148
  ] }),
8003
- /* @__PURE__ */ jsxRuntime.jsxs("div", { dir: "ltr", className: "relative space-y-1.5", children: [
8004
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ROW_GRID, children: [
8005
- /* @__PURE__ */ jsxRuntime.jsx("span", {}),
8006
- /* @__PURE__ */ jsxRuntime.jsx(
8007
- "div",
8008
- {
8009
- role: "slider",
8010
- tabIndex: 0,
8011
- "aria-label": labels.seek,
8012
- "aria-valuemin": 0,
8013
- "aria-valuemax": Math.round(duration),
8014
- "aria-valuenow": Math.round(currentTime),
8015
- "aria-valuetext": labels.seekValue(
8016
- formatClock(currentTime),
8017
- formatClock(duration)
8018
- ),
8019
- onKeyDown: onSeekKey,
8020
- onClick: (e) => seekTo(timeAtPointer(e.clientX, e.currentTarget, view)),
8021
- className: "focus-visible:ring-ring cursor-pointer rounded focus-visible:ring-2 focus-visible:outline-none",
8022
- children: /* @__PURE__ */ jsxRuntime.jsx(Waveform, { peaks, view, currentTime })
8023
- }
8024
- )
8025
- ] }),
8026
- visibleSpeakers.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
8027
- SpeakerLanes,
8028
- {
8029
- speakers: visibleSpeakers,
8030
- segments: visibleSegments,
8031
- view,
8032
- playingId,
8033
- onPlaySegment: playSegment,
8034
- onPause: pause,
8035
- onSeek: seekTo,
8036
- labels
8037
- },
8038
- src ?? ""
8039
- ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground py-2 text-center text-xs", children: speakers.length ? labels.allSpeakersHidden : labels.noActivity }),
8040
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkS5RVSXDV_cjs.cn(ROW_GRID, "h-4"), "aria-hidden": "true", children: [
8041
- /* @__PURE__ */ jsxRuntime.jsx("span", {}),
8042
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground relative text-[11px] tabular-nums", children: ticksFor(view).map((t) => /* @__PURE__ */ jsxRuntime.jsx(
8043
- "span",
8044
- {
8045
- className: "absolute -translate-x-1/2",
8046
- style: {
8047
- // rtl-ignore -- time axis inside the player's dir="ltr" timeline
8048
- left: `${viewFraction(t, view) * 100}%`
8149
+ /* @__PURE__ */ jsxRuntime.jsxs(
8150
+ "div",
8151
+ {
8152
+ id: lanesId,
8153
+ dir: "ltr",
8154
+ className: chunkS5RVSXDV_cjs.cn(
8155
+ "relative space-y-1.5",
8156
+ // No lane labels to line up with, so the waveform takes the full width.
8157
+ !showLanes && "[--tp-label:0px]"
8158
+ ),
8159
+ children: [
8160
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ROW_GRID, children: [
8161
+ /* @__PURE__ */ jsxRuntime.jsx("span", {}),
8162
+ /* @__PURE__ */ jsxRuntime.jsx(
8163
+ "div",
8164
+ {
8165
+ role: "slider",
8166
+ tabIndex: 0,
8167
+ "aria-label": labels.seek,
8168
+ "aria-valuemin": 0,
8169
+ "aria-valuemax": Math.round(duration),
8170
+ "aria-valuenow": Math.round(currentTime),
8171
+ "aria-valuetext": labels.seekValue(
8172
+ formatClock(currentTime),
8173
+ formatClock(duration)
8174
+ ),
8175
+ onKeyDown: onSeekKey,
8176
+ onClick: (e) => seekTo(timeAtPointer(e.clientX, e.currentTarget, view)),
8177
+ className: "focus-visible:ring-ring cursor-pointer rounded focus-visible:ring-2 focus-visible:outline-none",
8178
+ children: /* @__PURE__ */ jsxRuntime.jsx(Waveform, { peaks, view, currentTime })
8179
+ }
8180
+ )
8181
+ ] }),
8182
+ !showLanes ? null : visibleSpeakers.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
8183
+ SpeakerLanes,
8184
+ {
8185
+ speakers: visibleSpeakers,
8186
+ segments: visibleSegments,
8187
+ view,
8188
+ playingId,
8189
+ onPlaySegment: playSegment,
8190
+ onPause: pause,
8191
+ onSeek: seekTo,
8192
+ labels
8049
8193
  },
8050
- children: formatClock(t)
8051
- },
8052
- t
8053
- )) })
8054
- ] }),
8055
- playheadVisible && /* @__PURE__ */ jsxRuntime.jsxs(
8056
- "div",
8057
- {
8058
- "aria-hidden": "true",
8059
- className: "pointer-events-none absolute inset-y-0",
8060
- style: {
8061
- // rtl-ignore -- time axis inside the player's dir="ltr" timeline
8062
- left: `calc(${TRACK_OFFSET} + (100% - ${TRACK_OFFSET}) * ${playhead})`
8063
- },
8064
- children: [
8065
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary-600 absolute inset-y-0 w-0.5 -translate-x-1/2" }),
8066
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary-800 absolute -top-5 -translate-x-1/2 rounded px-1 text-[10px] font-medium text-white tabular-nums", children: formatClock(currentTime) })
8067
- ]
8068
- }
8069
- )
8070
- ] }),
8071
- /* @__PURE__ */ jsxRuntime.jsxs("div", { dir: "ltr", className: chunkS5RVSXDV_cjs.cn(ROW_GRID, "mt-3 items-start"), children: [
8194
+ src ?? ""
8195
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground py-2 text-center text-xs", children: speakers.length ? labels.allSpeakersHidden : labels.noActivity }),
8196
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkS5RVSXDV_cjs.cn(ROW_GRID, "h-4"), "aria-hidden": "true", children: [
8197
+ /* @__PURE__ */ jsxRuntime.jsx("span", {}),
8198
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground relative text-[11px] tabular-nums", children: ticksFor(view).map((t, i) => /* @__PURE__ */ jsxRuntime.jsx(
8199
+ "span",
8200
+ {
8201
+ className: chunkS5RVSXDV_cjs.cn(
8202
+ "absolute -translate-x-1/2",
8203
+ i % 2 === 1 && "hidden @md:inline"
8204
+ ),
8205
+ style: {
8206
+ // rtl-ignore -- time axis inside the player's dir="ltr" timeline
8207
+ left: `${viewFraction(t, view) * 100}%`
8208
+ },
8209
+ children: formatClock(t)
8210
+ },
8211
+ t
8212
+ )) })
8213
+ ] }),
8214
+ playheadVisible && /* @__PURE__ */ jsxRuntime.jsxs(
8215
+ "div",
8216
+ {
8217
+ "aria-hidden": "true",
8218
+ className: "pointer-events-none absolute inset-y-0",
8219
+ style: {
8220
+ // rtl-ignore -- time axis inside the player's dir="ltr" timeline
8221
+ left: `calc(${TRACK_OFFSET} + (100% - ${TRACK_OFFSET}) * ${playhead})`
8222
+ },
8223
+ children: [
8224
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary-600 absolute inset-y-0 w-0.5 -translate-x-1/2" }),
8225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary-800 absolute -top-5 -translate-x-1/2 rounded px-1 text-[10px] font-medium text-white tabular-nums", children: formatClock(currentTime) })
8226
+ ]
8227
+ }
8228
+ )
8229
+ ]
8230
+ }
8231
+ ),
8232
+ showLanes && /* @__PURE__ */ jsxRuntime.jsxs("div", { dir: "ltr", className: chunkS5RVSXDV_cjs.cn(ROW_GRID, "mt-3 items-start"), children: [
8072
8233
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
8073
8234
  /* @__PURE__ */ jsxRuntime.jsx(
8074
8235
  chunkFSARTLUE_cjs.Button,
@@ -8124,106 +8285,115 @@ function TranscriptPlayer({
8124
8285
  ]
8125
8286
  }
8126
8287
  ),
8127
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_18rem]", children: [
8128
- /* @__PURE__ */ jsxRuntime.jsxs(
8129
- "section",
8130
- {
8131
- "aria-labelledby": transcriptHeadingId,
8132
- className: "border-border bg-card text-card-foreground rounded-xl border p-4",
8133
- children: [
8134
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex flex-wrap items-center gap-3", children: [
8135
- /* @__PURE__ */ jsxRuntime.jsx("h3", { id: transcriptHeadingId, className: "text-base font-semibold", children: labels.transcript }),
8136
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-40 flex-1", children: [
8137
- /* @__PURE__ */ jsxRuntime.jsx(
8138
- lucideReact.Search,
8139
- {
8140
- "aria-hidden": "true",
8141
- className: "text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 h-4 w-4 -translate-y-1/2"
8142
- }
8143
- ),
8288
+ /* @__PURE__ */ jsxRuntime.jsxs(
8289
+ "div",
8290
+ {
8291
+ className: chunkS5RVSXDV_cjs.cn(
8292
+ "grid grid-cols-1 gap-4",
8293
+ showSpeakerPanel && "lg:grid-cols-[minmax(0,1fr)_18rem]"
8294
+ ),
8295
+ children: [
8296
+ /* @__PURE__ */ jsxRuntime.jsxs(
8297
+ "section",
8298
+ {
8299
+ "aria-labelledby": transcriptHeadingId,
8300
+ className: "border-border bg-card text-card-foreground rounded-xl border p-3 @md:p-4",
8301
+ children: [
8302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex flex-wrap items-center gap-3", children: [
8303
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { id: transcriptHeadingId, className: "text-base font-semibold", children: labels.transcript }),
8304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-40 flex-1", children: [
8305
+ /* @__PURE__ */ jsxRuntime.jsx(
8306
+ lucideReact.Search,
8307
+ {
8308
+ "aria-hidden": "true",
8309
+ className: "text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 h-4 w-4 -translate-y-1/2"
8310
+ }
8311
+ ),
8312
+ /* @__PURE__ */ jsxRuntime.jsx(
8313
+ chunkZ5S5JEJD_cjs.Input,
8314
+ {
8315
+ type: "search",
8316
+ label: labels.searchTranscript,
8317
+ hideLabel: true,
8318
+ placeholder: labels.searchPlaceholder,
8319
+ value: query,
8320
+ onChange: (e) => setQuery(e.target.value),
8321
+ size: "sm",
8322
+ className: "ps-8"
8323
+ }
8324
+ )
8325
+ ] }),
8326
+ /* @__PURE__ */ jsxRuntime.jsx(
8327
+ chunkUPWIJC6I_cjs.Select,
8328
+ {
8329
+ "aria-label": labels.showSpeakers,
8330
+ size: "sm",
8331
+ className: "w-44",
8332
+ value: filterValue,
8333
+ onValueChange: (v) => {
8334
+ if (v === ALL_SPEAKERS) setHidden(/* @__PURE__ */ new Set());
8335
+ else if (v.startsWith(SPEAKER_PREFIX)) {
8336
+ const id = v.slice(SPEAKER_PREFIX.length);
8337
+ setHidden(
8338
+ new Set(
8339
+ speakers.filter((s) => s.id !== id).map((s) => s.id)
8340
+ )
8341
+ );
8342
+ }
8343
+ },
8344
+ options: [
8345
+ { value: ALL_SPEAKERS, label: labels.allSpeakers },
8346
+ ...speakers.map((s) => ({
8347
+ value: SPEAKER_PREFIX + s.id,
8348
+ label: s.name
8349
+ })),
8350
+ ...filterValue === SOME_SPEAKERS ? [
8351
+ {
8352
+ value: SOME_SPEAKERS,
8353
+ label: labels.someSpeakers,
8354
+ disabled: true
8355
+ }
8356
+ ] : []
8357
+ ]
8358
+ }
8359
+ )
8360
+ ] }),
8144
8361
  /* @__PURE__ */ jsxRuntime.jsx(
8145
- chunkZ5S5JEJD_cjs.Input,
8362
+ TranscriptList,
8146
8363
  {
8147
- type: "search",
8148
- label: labels.searchTranscript,
8149
- hideLabel: true,
8150
- placeholder: labels.searchPlaceholder,
8151
- value: query,
8152
- onChange: (e) => setQuery(e.target.value),
8153
- size: "sm",
8154
- className: "ps-8"
8155
- }
8156
- )
8157
- ] }),
8158
- /* @__PURE__ */ jsxRuntime.jsx(
8159
- chunkUPWIJC6I_cjs.Select,
8160
- {
8161
- "aria-label": labels.showSpeakers,
8162
- size: "sm",
8163
- className: "w-44",
8164
- value: filterValue,
8165
- onValueChange: (v) => {
8166
- if (v === ALL_SPEAKERS) setHidden(/* @__PURE__ */ new Set());
8167
- else if (v.startsWith(SPEAKER_PREFIX)) {
8168
- const id = v.slice(SPEAKER_PREFIX.length);
8169
- setHidden(
8170
- new Set(
8171
- speakers.filter((s) => s.id !== id).map((s) => s.id)
8172
- )
8173
- );
8174
- }
8364
+ utterances: shown,
8365
+ speakersById,
8366
+ activeId: active?.id ?? null,
8367
+ playingId,
8368
+ query,
8369
+ onPlay: playUtterance,
8370
+ onPause: pause,
8371
+ labels,
8372
+ emptyMessage: utterances.length === 0 ? labels.noTranscript : labels.noMatches
8175
8373
  },
8176
- options: [
8177
- { value: ALL_SPEAKERS, label: labels.allSpeakers },
8178
- ...speakers.map((s) => ({
8179
- value: SPEAKER_PREFIX + s.id,
8180
- label: s.name
8181
- })),
8182
- ...filterValue === SOME_SPEAKERS ? [
8183
- {
8184
- value: SOME_SPEAKERS,
8185
- label: labels.someSpeakers,
8186
- disabled: true
8187
- }
8188
- ] : []
8189
- ]
8190
- }
8191
- )
8192
- ] }),
8374
+ src ?? ""
8375
+ )
8376
+ ]
8377
+ }
8378
+ ),
8379
+ showSpeakerPanel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
8193
8380
  /* @__PURE__ */ jsxRuntime.jsx(
8194
- TranscriptList,
8381
+ SpeakerPanel,
8195
8382
  {
8196
- utterances: shown,
8197
- speakersById,
8198
- activeId: active?.id ?? null,
8199
- playingId,
8200
- query,
8201
- onPlay: playUtterance,
8202
- onPause: pause,
8203
- labels,
8204
- emptyMessage: utterances.length === 0 ? labels.noTranscript : labels.noMatches
8205
- },
8206
- src ?? ""
8207
- )
8208
- ]
8209
- }
8210
- ),
8211
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
8212
- /* @__PURE__ */ jsxRuntime.jsx(
8213
- SpeakerPanel,
8214
- {
8215
- speakers,
8216
- talkTime: talk,
8217
- duration,
8218
- hidden,
8219
- onToggle: toggleSpeaker,
8220
- overlapping,
8221
- labels
8222
- }
8223
- ),
8224
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground bg-muted/50 rounded-xl p-4 text-xs", children: labels.hint })
8225
- ] })
8226
- ] })
8383
+ speakers,
8384
+ talkTime: talk,
8385
+ duration,
8386
+ hidden,
8387
+ onToggle: toggleSpeaker,
8388
+ overlapping,
8389
+ labels
8390
+ }
8391
+ ),
8392
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground bg-muted/50 rounded-xl p-4 text-xs", children: labels.hint })
8393
+ ] })
8394
+ ]
8395
+ }
8396
+ )
8227
8397
  ]
8228
8398
  }
8229
8399
  );
@@ -46041,11 +46211,11 @@ Object.defineProperty(exports, "unformatPhoneNumber", {
46041
46211
  });
46042
46212
  Object.defineProperty(exports, "miewebUIPreset", {
46043
46213
  enumerable: true,
46044
- get: function () { return chunkXWGPEIVB_cjs.miewebUIPreset; }
46214
+ get: function () { return chunk2UGMTGH2_cjs.miewebUIPreset; }
46045
46215
  });
46046
46216
  Object.defineProperty(exports, "miewebUISafelist", {
46047
46217
  enumerable: true,
46048
- get: function () { return chunkXWGPEIVB_cjs.miewebUISafelist; }
46218
+ get: function () { return chunk2UGMTGH2_cjs.miewebUISafelist; }
46049
46219
  });
46050
46220
  Object.defineProperty(exports, "Accordion", {
46051
46221
  enumerable: true,
@@ -47702,6 +47872,7 @@ exports.orderToMedication = orderToMedication;
47702
47872
  exports.parseTimeInput = parseTimeInput;
47703
47873
  exports.reconciliationPanelVariants = panelVariants;
47704
47874
  exports.subscribeWakeWarm = subscribeWakeWarm;
47875
+ exports.transcriptFromActivity = transcriptFromActivity;
47705
47876
  exports.useCamera = useCamera;
47706
47877
  exports.useCommandPalette = useCommandPalette;
47707
47878
  exports.useConnectionStatus = useConnectionStatus;