@proteos/ui 0.77.0 → 0.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +991 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +592 -2
- package/dist/index.d.ts +592 -2
- package/dist/index.js +969 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/data-table/data-table.scroll-restore.test.tsx +97 -0
- package/src/components/data-table/data-table.test.tsx +22 -2
- package/src/components/data-table/data-table.tsx +31 -1
- package/src/components/frame-strip/frame-strip.stories.tsx +61 -0
- package/src/components/frame-strip/frame-strip.test.tsx +112 -0
- package/src/components/frame-strip/frame-strip.tsx +131 -0
- package/src/components/frame-strip/index.ts +2 -0
- package/src/components/media-player/index.ts +22 -0
- package/src/components/media-player/media-controls.tsx +145 -0
- package/src/components/media-player/media-markers.tsx +108 -0
- package/src/components/media-player/media-peaks.test.ts +68 -0
- package/src/components/media-player/media-peaks.ts +78 -0
- package/src/components/media-player/media-player.stories.tsx +243 -0
- package/src/components/media-player/media-player.test.tsx +318 -0
- package/src/components/media-player/media-player.tsx +334 -0
- package/src/components/media-player/media-time.ts +27 -0
- package/src/components/media-player/media-timeline.test.tsx +133 -0
- package/src/components/media-player/media-timeline.tsx +78 -0
- package/src/components/media-player/media-video-stage.tsx +113 -0
- package/src/components/media-player/media-waveform.tsx +330 -0
- package/src/components/slider/index.ts +2 -0
- package/src/components/slider/slider.stories.tsx +32 -0
- package/src/components/slider/slider.test.tsx +35 -0
- package/src/components/slider/slider.tsx +89 -0
- package/src/index.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { cn, Button, Skeleton } from './chunk-XRN5MNDX.js';
|
|
2
2
|
export { Button, Skeleton, buttonStyles, cn, skeletonStyles } from './chunk-XRN5MNDX.js';
|
|
3
|
-
import { icons, Contact, Paperclip, BookText, Banknote, UsersRound, User, Link2, Braces, Brackets, ToggleLeft, CircleDot, Calendar, Hash, Type, File, FileImage, FileText, FileSpreadsheet, FileArchive, Loader2, X, ChevronLeft, ChevronRight, Shapes, Search, Phone, AudioLines, Video, Mic, AtSign, MessagesSquare, Camera, Send, Linkedin, MessageCircle, Mail, Pipette, Pencil, ChevronDown, GripVertical, SendHorizontal, CircleX, Download, AlertCircle, Undo2, ArrowRight, Check, CircleCheck, CircleAlert, Info } from 'lucide-react';
|
|
3
|
+
import { icons, Contact, Paperclip, BookText, Banknote, UsersRound, User, Link2, Braces, Brackets, ToggleLeft, CircleDot, Calendar, Hash, Type, File, FileImage, FileText, FileSpreadsheet, FileArchive, Loader2, X, ChevronLeft, ChevronRight, Shapes, Search, Phone, AudioLines, Video, Mic, AtSign, MessagesSquare, Camera, Send, Linkedin, MessageCircle, Mail, Pipette, Pencil, ChevronDown, GripVertical, SendHorizontal, CircleX, Download, Square, RotateCcw, Pause, Play, RotateCw, AlertCircle, Undo2, ArrowRight, Check, CircleCheck, CircleAlert, Info } from 'lucide-react';
|
|
4
4
|
import { tv } from 'tailwind-variants';
|
|
5
|
-
import { Tabs as Tabs$1, TabPanel, Tab, TabList, MenuTrigger as MenuTrigger$1, SubmenuTrigger as SubmenuTrigger$1, DialogTrigger, Popover as Popover$1, Dialog, DropZone, Text, FileTrigger, Heading, Calendar as Calendar$1, Button as Button$1, CalendarGrid, CalendarGridHeader, CalendarHeaderCell, CalendarGridBody, CalendarCell, CalendarStateContext, Label, Input as Input$1, ListBox, ListBoxItem, TooltipTrigger as TooltipTrigger$1, Tooltip as Tooltip$1, Breadcrumbs as Breadcrumbs$1, Breadcrumb, Link, Checkbox as Checkbox$1, CheckboxGroup as CheckboxGroup$1, FieldError, TextField, ComboBox, ComboBoxStateContext, Select as Select$1, SelectValue, ModalOverlay, Modal as Modal$1, DatePicker as DatePicker$1, Group, DateInput, DateSegment, Menu as Menu$1, MenuItem as MenuItem$1, Disclosure, DisclosurePanel, ProgressBar as ProgressBar$1, RadioGroup as RadioGroup$1, Radio as Radio$1, Separator as Separator$1, Switch as Switch$1, TextArea, TimeField as TimeField$1,
|
|
5
|
+
import { Tabs as Tabs$1, TabPanel, Tab, TabList, MenuTrigger as MenuTrigger$1, SubmenuTrigger as SubmenuTrigger$1, DialogTrigger, Popover as Popover$1, Dialog, DropZone, Text, FileTrigger, Heading, Calendar as Calendar$1, Button as Button$1, CalendarGrid, CalendarGridHeader, CalendarHeaderCell, CalendarGridBody, CalendarCell, CalendarStateContext, Label, Input as Input$1, ListBox, ListBoxItem, TooltipTrigger as TooltipTrigger$1, Tooltip as Tooltip$1, Breadcrumbs as Breadcrumbs$1, Breadcrumb, Link, Checkbox as Checkbox$1, CheckboxGroup as CheckboxGroup$1, FieldError, TextField, ComboBox, ComboBoxStateContext, Select as Select$1, SelectValue, ModalOverlay, Modal as Modal$1, DatePicker as DatePicker$1, Group, DateInput, DateSegment, ToggleButtonGroup, ToggleButton, Slider as Slider$1, SliderTrack, SliderThumb, Menu as Menu$1, MenuItem as MenuItem$1, Disclosure, DisclosurePanel, ProgressBar as ProgressBar$1, RadioGroup as RadioGroup$1, Radio as Radio$1, Separator as Separator$1, Switch as Switch$1, TextArea, TimeField as TimeField$1, UNSTABLE_ToastQueue, UNSTABLE_ToastRegion, UNSTABLE_Toast, UNSTABLE_ToastContent, DatePickerStateContext } from 'react-aria-components';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import { lazy, createContext, useContext, useState,
|
|
7
|
+
import { lazy, createContext, memo, useRef, useEffect, useContext, useState, useMemo, Children, isValidElement, useLayoutEffect, useSyncExternalStore, useCallback, Suspense, useId, Fragment as Fragment$1 } from 'react';
|
|
8
8
|
import { formatAmount, parseAmount } from '@proteos/sdk';
|
|
9
9
|
import { draggable, dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
10
10
|
import { extractClosestEdge, attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
@@ -125,12 +125,12 @@ function formatFileSize(bytes) {
|
|
|
125
125
|
if (bytes < 1024) return `${bytes} B`;
|
|
126
126
|
const units = ["KB", "MB", "GB", "TB"];
|
|
127
127
|
let size = bytes / 1024;
|
|
128
|
-
let
|
|
129
|
-
while (size >= 1024 &&
|
|
128
|
+
let unit2 = 0;
|
|
129
|
+
while (size >= 1024 && unit2 < units.length - 1) {
|
|
130
130
|
size /= 1024;
|
|
131
|
-
|
|
131
|
+
unit2 += 1;
|
|
132
132
|
}
|
|
133
|
-
return `${size < 10 ? size.toFixed(1) : Math.round(size)} ${units[
|
|
133
|
+
return `${size < 10 ? size.toFixed(1) : Math.round(size)} ${units[unit2]}`;
|
|
134
134
|
}
|
|
135
135
|
function FileField({
|
|
136
136
|
value,
|
|
@@ -3997,13 +3997,35 @@ function DataTable({
|
|
|
3997
3997
|
setListOffset((prev) => prev === top ? prev : top);
|
|
3998
3998
|
});
|
|
3999
3999
|
const headingHeight = groupHeaderHeight ?? rowHeight;
|
|
4000
|
+
const [isScrollerAttached, setIsScrollerAttached] = useState(false);
|
|
4001
|
+
useLayoutEffect(() => setIsScrollerAttached(true), []);
|
|
4000
4002
|
const virtualizer = useVirtualizer({
|
|
4003
|
+
enabled: initialScrollOffset === void 0 || isScrollerAttached,
|
|
4001
4004
|
count: listItems.length,
|
|
4002
4005
|
getScrollElement: () => scrollerRef.current,
|
|
4003
4006
|
estimateSize: (index) => listItems[index]?.kind === "group" ? headingHeight : rowHeight,
|
|
4004
4007
|
overscan,
|
|
4005
4008
|
scrollMargin: listOffset,
|
|
4006
|
-
|
|
4009
|
+
// Read once, with the scroller attached (see `enabled`). Clamp the restored
|
|
4010
|
+
// offset to what the scroller will be able to reach: while the skeleton
|
|
4011
|
+
// shows, or when the list shrank since the visit, the browser clamps
|
|
4012
|
+
// scrollTop WITHOUT firing a scroll event, and the virtualizer — which only
|
|
4013
|
+
// re-reads its offset on scroll events — would sit past the rows and paint
|
|
4014
|
+
// empty. The reach comes from the row data, not `scrollHeight`: the disabled
|
|
4015
|
+
// first render committed an empty spacer, so the DOM can't report it yet.
|
|
4016
|
+
...initialScrollOffset !== void 0 ? {
|
|
4017
|
+
initialOffset: () => {
|
|
4018
|
+
const el = scrollerRef.current;
|
|
4019
|
+
if (!el) return 0;
|
|
4020
|
+
const estimatedSize = listItems.reduce(
|
|
4021
|
+
(sum, item) => sum + (item.kind === "group" ? headingHeight : rowHeight),
|
|
4022
|
+
0
|
|
4023
|
+
);
|
|
4024
|
+
const listTop = listRef.current?.offsetTop ?? 0;
|
|
4025
|
+
const reachable = listTop + estimatedSize - el.clientHeight;
|
|
4026
|
+
return Math.max(0, Math.min(initialScrollOffset, reachable));
|
|
4027
|
+
}
|
|
4028
|
+
} : {}
|
|
4007
4029
|
});
|
|
4008
4030
|
const sentinelRef = useInfiniteScrollSentinel({
|
|
4009
4031
|
onIntersect: () => {
|
|
@@ -6028,6 +6050,103 @@ function FileViewer({
|
|
|
6028
6050
|
const skeleton = /* @__PURE__ */ jsx(Skeleton, { "aria-label": `Loading preview of ${name}`, className: "h-full w-full rounded-none" });
|
|
6029
6051
|
return /* @__PURE__ */ jsx("div", { className: cn(fileViewerStyles(), className), style: { height: heightPx }, children: !src ? skeleton : kind === "image" ? /* @__PURE__ */ jsx(ImageView, { name, src, ...onDownload ? { onDownload } : {} }) : kind === "video" ? /* @__PURE__ */ jsx(VideoView, { name, src }) : /* @__PURE__ */ jsx(Suspense, { fallback: skeleton, children: /* @__PURE__ */ jsx(PdfView, { name, src, ...onDownload ? { onDownload } : {} }) }) });
|
|
6030
6052
|
}
|
|
6053
|
+
|
|
6054
|
+
// src/components/media-player/media-time.ts
|
|
6055
|
+
var pad = (value) => String(value).padStart(2, "0");
|
|
6056
|
+
function formatMediaTime(seconds) {
|
|
6057
|
+
const total = Math.max(0, Math.floor(Number.isFinite(seconds) ? seconds : 0));
|
|
6058
|
+
const hours = Math.floor(total / 3600);
|
|
6059
|
+
const minutes = Math.floor(total % 3600 / 60);
|
|
6060
|
+
const rest = total % 60;
|
|
6061
|
+
return hours > 0 ? `${hours}:${pad(minutes)}:${pad(rest)}` : `${pad(minutes)}:${pad(rest)}`;
|
|
6062
|
+
}
|
|
6063
|
+
var unit = (value, name) => `${value} ${name}${value === 1 ? "" : "s"}`;
|
|
6064
|
+
function spokenMediaTime(seconds) {
|
|
6065
|
+
const total = Math.max(0, Math.floor(Number.isFinite(seconds) ? seconds : 0));
|
|
6066
|
+
const hours = Math.floor(total / 3600);
|
|
6067
|
+
const minutes = Math.floor(total % 3600 / 60);
|
|
6068
|
+
const rest = total % 60;
|
|
6069
|
+
return [
|
|
6070
|
+
hours > 0 ? unit(hours, "hour") : "",
|
|
6071
|
+
minutes > 0 ? unit(minutes, "minute") : "",
|
|
6072
|
+
rest > 0 || total === 0 ? unit(rest, "second") : ""
|
|
6073
|
+
].filter(Boolean).join(" ");
|
|
6074
|
+
}
|
|
6075
|
+
var frameStripStyles = tv({
|
|
6076
|
+
slots: {
|
|
6077
|
+
root: "flex shrink-0 gap-2 overflow-x-auto overscroll-x-contain scroll-px-[18px] px-[18px] py-3",
|
|
6078
|
+
item: [
|
|
6079
|
+
"group flex w-[120px] shrink-0 cursor-pointer flex-col gap-1.5 rounded-md p-1 outline-none",
|
|
6080
|
+
"transition-[background-color,box-shadow] duration-150",
|
|
6081
|
+
"hovered:bg-surface-2",
|
|
6082
|
+
"pressed:bg-surface-3",
|
|
6083
|
+
"data-[focus-visible]:shadow-[var(--shadow-focus)]"
|
|
6084
|
+
],
|
|
6085
|
+
thumbnail: [
|
|
6086
|
+
"relative aspect-video w-full overflow-hidden rounded-sm border border-rule bg-surface-2",
|
|
6087
|
+
"*:size-full *:object-cover",
|
|
6088
|
+
"transition-[border-color,box-shadow] duration-150",
|
|
6089
|
+
"group-data-[hovered]:border-rule-strong",
|
|
6090
|
+
"group-data-[selected]:border-ink group-data-[selected]:shadow-[inset_0_0_0_1px_var(--color-ink)]"
|
|
6091
|
+
],
|
|
6092
|
+
caption: "flex min-w-0 items-baseline gap-1.5 px-0.5",
|
|
6093
|
+
label: [
|
|
6094
|
+
"min-w-0 flex-1 truncate text-[12px] leading-4 text-ink-2",
|
|
6095
|
+
"group-data-[selected]:font-medium group-data-[selected]:text-ink"
|
|
6096
|
+
],
|
|
6097
|
+
time: "shrink-0 font-mono text-[11px] leading-4 tabular-nums text-ink-4"
|
|
6098
|
+
}
|
|
6099
|
+
});
|
|
6100
|
+
function FrameStrip({ items, selectedKey, onSelect, className, ...props }) {
|
|
6101
|
+
const styles4 = frameStripStyles();
|
|
6102
|
+
const rootRef = useRef(null);
|
|
6103
|
+
useEffect(() => {
|
|
6104
|
+
const root = rootRef.current;
|
|
6105
|
+
if (selectedKey === void 0 || !root) return;
|
|
6106
|
+
for (const element of root.querySelectorAll("[data-frame-key]")) {
|
|
6107
|
+
if (element.dataset.frameKey !== selectedKey) continue;
|
|
6108
|
+
if (typeof element.scrollIntoView === "function")
|
|
6109
|
+
element.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
6110
|
+
break;
|
|
6111
|
+
}
|
|
6112
|
+
}, [selectedKey]);
|
|
6113
|
+
if (items.length === 0) return null;
|
|
6114
|
+
const isLabelled = props["aria-label"] !== void 0 || props["aria-labelledby"] !== void 0;
|
|
6115
|
+
return /* @__PURE__ */ jsx(
|
|
6116
|
+
ToggleButtonGroup,
|
|
6117
|
+
{
|
|
6118
|
+
...isLabelled ? {} : { "aria-label": "Frames" },
|
|
6119
|
+
...props,
|
|
6120
|
+
ref: rootRef,
|
|
6121
|
+
orientation: "horizontal",
|
|
6122
|
+
selectionMode: "single",
|
|
6123
|
+
disallowEmptySelection: true,
|
|
6124
|
+
selectedKeys: selectedKey === void 0 ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([selectedKey]),
|
|
6125
|
+
onSelectionChange: (keys) => {
|
|
6126
|
+
const [next] = Array.from(keys);
|
|
6127
|
+
if (next !== void 0) onSelect(String(next));
|
|
6128
|
+
},
|
|
6129
|
+
className: cn(styles4.root(), className),
|
|
6130
|
+
children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
6131
|
+
ToggleButton,
|
|
6132
|
+
{
|
|
6133
|
+
id: item.key,
|
|
6134
|
+
"data-frame-key": item.key,
|
|
6135
|
+
"aria-label": `${item.label}, at ${formatMediaTime(item.at)}`,
|
|
6136
|
+
className: styles4.item(),
|
|
6137
|
+
children: [
|
|
6138
|
+
/* @__PURE__ */ jsx("span", { className: styles4.thumbnail(), children: item.thumbnail }),
|
|
6139
|
+
/* @__PURE__ */ jsxs("span", { className: styles4.caption(), children: [
|
|
6140
|
+
/* @__PURE__ */ jsx("span", { className: styles4.label(), children: item.label }),
|
|
6141
|
+
/* @__PURE__ */ jsx("span", { className: styles4.time(), children: formatMediaTime(item.at) })
|
|
6142
|
+
] })
|
|
6143
|
+
]
|
|
6144
|
+
},
|
|
6145
|
+
item.key
|
|
6146
|
+
))
|
|
6147
|
+
}
|
|
6148
|
+
);
|
|
6149
|
+
}
|
|
6031
6150
|
var glowFrameStyles = tv({
|
|
6032
6151
|
slots: {
|
|
6033
6152
|
room: "glow-room flex min-h-0 flex-col",
|
|
@@ -6232,6 +6351,847 @@ function Input({
|
|
|
6232
6351
|
}
|
|
6233
6352
|
);
|
|
6234
6353
|
}
|
|
6354
|
+
var sliderStyles = tv({
|
|
6355
|
+
slots: {
|
|
6356
|
+
root: "flex w-full items-center",
|
|
6357
|
+
track: "group relative h-[18px] w-full cursor-pointer data-[disabled]:cursor-default",
|
|
6358
|
+
rail: "absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 overflow-hidden rounded-pill bg-surface-3",
|
|
6359
|
+
fill: "h-full bg-ink",
|
|
6360
|
+
thumb: [
|
|
6361
|
+
"top-1/2 size-3 rounded-pill bg-ink",
|
|
6362
|
+
"shadow-[var(--shadow-rest)]",
|
|
6363
|
+
"data-[focus-visible]:shadow-[var(--shadow-focus)]",
|
|
6364
|
+
"data-[disabled]:hidden"
|
|
6365
|
+
]
|
|
6366
|
+
}
|
|
6367
|
+
});
|
|
6368
|
+
function Slider({
|
|
6369
|
+
value,
|
|
6370
|
+
onChange,
|
|
6371
|
+
onChangeEnd,
|
|
6372
|
+
valueText,
|
|
6373
|
+
className,
|
|
6374
|
+
...props
|
|
6375
|
+
}) {
|
|
6376
|
+
const styles4 = sliderStyles();
|
|
6377
|
+
const inputRef = useRef(null);
|
|
6378
|
+
useLayoutEffect(() => {
|
|
6379
|
+
if (valueText !== void 0) inputRef.current?.setAttribute("aria-valuetext", valueText);
|
|
6380
|
+
});
|
|
6381
|
+
return /* @__PURE__ */ jsx(
|
|
6382
|
+
Slider$1,
|
|
6383
|
+
{
|
|
6384
|
+
...props,
|
|
6385
|
+
value,
|
|
6386
|
+
...onChange ? { onChange } : {},
|
|
6387
|
+
...onChangeEnd ? { onChangeEnd } : {},
|
|
6388
|
+
className: (renderProps) => cn(styles4.root(), typeof className === "function" ? className(renderProps) : className),
|
|
6389
|
+
children: /* @__PURE__ */ jsx(SliderTrack, { className: styles4.track(), children: ({ state }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6390
|
+
/* @__PURE__ */ jsx("div", { className: styles4.rail(), children: /* @__PURE__ */ jsx(
|
|
6391
|
+
"div",
|
|
6392
|
+
{
|
|
6393
|
+
className: styles4.fill(),
|
|
6394
|
+
style: { width: `${state.getThumbPercent(0) * 100}%` }
|
|
6395
|
+
}
|
|
6396
|
+
) }),
|
|
6397
|
+
/* @__PURE__ */ jsx(SliderThumb, { inputRef, className: styles4.thumb() })
|
|
6398
|
+
] }) })
|
|
6399
|
+
}
|
|
6400
|
+
);
|
|
6401
|
+
}
|
|
6402
|
+
|
|
6403
|
+
// src/components/media-player/media-peaks.ts
|
|
6404
|
+
var MAX_DECODE_BYTES = 50 * 1024 * 1024;
|
|
6405
|
+
var DECODE_SAMPLE_RATE = 8e3;
|
|
6406
|
+
var PEAK_BUCKETS = 4e3;
|
|
6407
|
+
var SAMPLES_PER_BUCKET = 256;
|
|
6408
|
+
function peaksFromChannels(channels, buckets = PEAK_BUCKETS) {
|
|
6409
|
+
const length = channels[0]?.length ?? 0;
|
|
6410
|
+
const peaks = new Float32Array(buckets);
|
|
6411
|
+
if (length === 0) return peaks;
|
|
6412
|
+
const stride = Math.max(1, Math.floor(length / buckets / SAMPLES_PER_BUCKET));
|
|
6413
|
+
let loudest = 0;
|
|
6414
|
+
for (let bucket = 0; bucket < buckets; bucket++) {
|
|
6415
|
+
const start = Math.floor(bucket / buckets * length);
|
|
6416
|
+
const end = Math.floor((bucket + 1) / buckets * length);
|
|
6417
|
+
let sum = 0;
|
|
6418
|
+
let count = 0;
|
|
6419
|
+
for (let index = start; index < end; index += stride) {
|
|
6420
|
+
let sample = 0;
|
|
6421
|
+
for (const channel of channels) sample = Math.max(sample, Math.abs(channel[index] ?? 0));
|
|
6422
|
+
sum += sample * sample;
|
|
6423
|
+
count++;
|
|
6424
|
+
}
|
|
6425
|
+
const level = count > 0 ? Math.sqrt(sum / count) : 0;
|
|
6426
|
+
peaks[bucket] = level;
|
|
6427
|
+
if (level > loudest) loudest = level;
|
|
6428
|
+
}
|
|
6429
|
+
if (loudest > 0)
|
|
6430
|
+
for (let bucket = 0; bucket < buckets; bucket++) peaks[bucket] = (peaks[bucket] ?? 0) / loudest;
|
|
6431
|
+
return peaks;
|
|
6432
|
+
}
|
|
6433
|
+
function maskPeaks(peaks, duration, segments) {
|
|
6434
|
+
const masked = new Float32Array(peaks.length);
|
|
6435
|
+
if (duration <= 0) return masked;
|
|
6436
|
+
for (const [start, end] of segments) {
|
|
6437
|
+
const from = Math.max(0, Math.floor(start / duration * peaks.length));
|
|
6438
|
+
const to = Math.min(peaks.length, Math.ceil(end / duration * peaks.length));
|
|
6439
|
+
for (let bucket = from; bucket < to; bucket++) masked[bucket] = peaks[bucket] ?? 0;
|
|
6440
|
+
}
|
|
6441
|
+
return masked;
|
|
6442
|
+
}
|
|
6443
|
+
async function decodePeaks(blob) {
|
|
6444
|
+
const context = new OfflineAudioContext(1, 1, DECODE_SAMPLE_RATE);
|
|
6445
|
+
const buffer = await context.decodeAudioData(await blob.arrayBuffer());
|
|
6446
|
+
const channels = Array.from(
|
|
6447
|
+
{ length: buffer.numberOfChannels },
|
|
6448
|
+
(_, index) => buffer.getChannelData(index)
|
|
6449
|
+
);
|
|
6450
|
+
return { peaks: peaksFromChannels(channels), duration: buffer.duration };
|
|
6451
|
+
}
|
|
6452
|
+
var mediaPlayerStyles = tv({
|
|
6453
|
+
slots: {
|
|
6454
|
+
root: "flex min-h-0 flex-1 flex-col",
|
|
6455
|
+
stage: "relative flex min-h-0 flex-1 flex-col"
|
|
6456
|
+
}
|
|
6457
|
+
});
|
|
6458
|
+
var MediaPlayerContext = createContext(null);
|
|
6459
|
+
function useMediaPlayer() {
|
|
6460
|
+
const context = useContext(MediaPlayerContext);
|
|
6461
|
+
if (!context) throw new Error("useMediaPlayer must be used inside a MediaPlayer");
|
|
6462
|
+
return context;
|
|
6463
|
+
}
|
|
6464
|
+
var HAVE_METADATA = 1;
|
|
6465
|
+
function MediaPlayer({
|
|
6466
|
+
source,
|
|
6467
|
+
label,
|
|
6468
|
+
kind = "audio",
|
|
6469
|
+
onError,
|
|
6470
|
+
className,
|
|
6471
|
+
children
|
|
6472
|
+
}) {
|
|
6473
|
+
const [media, setMedia] = useState(null);
|
|
6474
|
+
const [src, setSrc] = useState(null);
|
|
6475
|
+
const [loaded, setLoaded] = useState(null);
|
|
6476
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
6477
|
+
const [currentTime, setCurrentTime] = useState(0);
|
|
6478
|
+
const [mediaDuration, setMediaDuration] = useState(0);
|
|
6479
|
+
const [playbackRate, setPlaybackRateState] = useState(1);
|
|
6480
|
+
const [waveformStatus, setWaveformStatus] = useState("decoding");
|
|
6481
|
+
const [decoded, setDecoded] = useState(null);
|
|
6482
|
+
const blob = "blob" in source ? source.blob : null;
|
|
6483
|
+
const url = "url" in source ? source.url : null;
|
|
6484
|
+
const givenPeaks = "url" in source ? source.peaks ?? null : null;
|
|
6485
|
+
const givenDuration = source.duration ?? null;
|
|
6486
|
+
useEffect(() => {
|
|
6487
|
+
if (!blob) {
|
|
6488
|
+
setSrc(url);
|
|
6489
|
+
return;
|
|
6490
|
+
}
|
|
6491
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
6492
|
+
setSrc(objectUrl);
|
|
6493
|
+
return () => URL.revokeObjectURL(objectUrl);
|
|
6494
|
+
}, [blob, url]);
|
|
6495
|
+
useEffect(() => {
|
|
6496
|
+
if (!blob) {
|
|
6497
|
+
if (givenPeaks && givenDuration !== null) {
|
|
6498
|
+
setDecoded({ peaks: givenPeaks, duration: givenDuration });
|
|
6499
|
+
setWaveformStatus("ready");
|
|
6500
|
+
} else {
|
|
6501
|
+
setDecoded(null);
|
|
6502
|
+
setWaveformStatus("unavailable");
|
|
6503
|
+
}
|
|
6504
|
+
return;
|
|
6505
|
+
}
|
|
6506
|
+
setDecoded(null);
|
|
6507
|
+
if (blob.size > MAX_DECODE_BYTES) {
|
|
6508
|
+
setWaveformStatus("unavailable");
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6511
|
+
setWaveformStatus("decoding");
|
|
6512
|
+
let isCancelled = false;
|
|
6513
|
+
decodePeaks(blob).then((result) => {
|
|
6514
|
+
if (isCancelled) return;
|
|
6515
|
+
setDecoded(result);
|
|
6516
|
+
setWaveformStatus("ready");
|
|
6517
|
+
}).catch(() => {
|
|
6518
|
+
if (!isCancelled) setWaveformStatus("unavailable");
|
|
6519
|
+
});
|
|
6520
|
+
return () => {
|
|
6521
|
+
isCancelled = true;
|
|
6522
|
+
};
|
|
6523
|
+
}, [blob, givenPeaks, givenDuration]);
|
|
6524
|
+
useEffect(() => {
|
|
6525
|
+
if (!media) return;
|
|
6526
|
+
const syncTime = () => setCurrentTime(media.currentTime);
|
|
6527
|
+
const syncDuration = () => setMediaDuration(Number.isFinite(media.duration) ? media.duration : 0);
|
|
6528
|
+
const syncLoaded = () => {
|
|
6529
|
+
setLoaded(media);
|
|
6530
|
+
syncDuration();
|
|
6531
|
+
};
|
|
6532
|
+
const syncEmptied = () => {
|
|
6533
|
+
setLoaded(null);
|
|
6534
|
+
setMediaDuration(0);
|
|
6535
|
+
setCurrentTime(0);
|
|
6536
|
+
};
|
|
6537
|
+
const syncPlaying = () => setIsPlaying(!media.paused && !media.ended);
|
|
6538
|
+
const handleError = () => onError?.();
|
|
6539
|
+
if (media.readyState >= HAVE_METADATA) syncLoaded();
|
|
6540
|
+
const events = [
|
|
6541
|
+
["timeupdate", syncTime],
|
|
6542
|
+
["seeked", syncTime],
|
|
6543
|
+
["loadedmetadata", syncLoaded],
|
|
6544
|
+
["durationchange", syncDuration],
|
|
6545
|
+
["emptied", syncEmptied],
|
|
6546
|
+
["play", syncPlaying],
|
|
6547
|
+
["pause", syncPlaying],
|
|
6548
|
+
["ended", syncPlaying],
|
|
6549
|
+
["error", handleError]
|
|
6550
|
+
];
|
|
6551
|
+
for (const [name, handler] of events) media.addEventListener(name, handler);
|
|
6552
|
+
return () => {
|
|
6553
|
+
for (const [name, handler] of events) media.removeEventListener(name, handler);
|
|
6554
|
+
media.pause();
|
|
6555
|
+
};
|
|
6556
|
+
}, [media, onError]);
|
|
6557
|
+
const duration = mediaDuration || givenDuration || decoded?.duration || 0;
|
|
6558
|
+
const isReady = media !== null && loaded === media;
|
|
6559
|
+
const toggle = useCallback(() => {
|
|
6560
|
+
if (!media) return;
|
|
6561
|
+
if (media.paused || media.ended) {
|
|
6562
|
+
void media.play().catch(() => void 0);
|
|
6563
|
+
} else {
|
|
6564
|
+
media.pause();
|
|
6565
|
+
}
|
|
6566
|
+
}, [media]);
|
|
6567
|
+
const seek = useCallback(
|
|
6568
|
+
(seconds) => {
|
|
6569
|
+
if (!media) return;
|
|
6570
|
+
const limit = Number.isFinite(media.duration) ? media.duration : duration > 0 ? duration : seconds;
|
|
6571
|
+
const next = Math.max(0, Math.min(limit, seconds));
|
|
6572
|
+
media.currentTime = next;
|
|
6573
|
+
setCurrentTime(next);
|
|
6574
|
+
},
|
|
6575
|
+
[media, duration]
|
|
6576
|
+
);
|
|
6577
|
+
const skip = useCallback(
|
|
6578
|
+
(seconds) => {
|
|
6579
|
+
if (media) seek(media.currentTime + seconds);
|
|
6580
|
+
},
|
|
6581
|
+
[media, seek]
|
|
6582
|
+
);
|
|
6583
|
+
const stop = useCallback(() => {
|
|
6584
|
+
media?.pause();
|
|
6585
|
+
seek(0);
|
|
6586
|
+
}, [media, seek]);
|
|
6587
|
+
const setPlaybackRate = useCallback(
|
|
6588
|
+
(rate) => {
|
|
6589
|
+
if (media) media.playbackRate = rate;
|
|
6590
|
+
setPlaybackRateState(rate);
|
|
6591
|
+
},
|
|
6592
|
+
[media]
|
|
6593
|
+
);
|
|
6594
|
+
const value = useMemo(
|
|
6595
|
+
() => ({
|
|
6596
|
+
media,
|
|
6597
|
+
mediaRef: setMedia,
|
|
6598
|
+
src,
|
|
6599
|
+
isReady,
|
|
6600
|
+
isPlaying,
|
|
6601
|
+
currentTime,
|
|
6602
|
+
duration,
|
|
6603
|
+
playbackRate,
|
|
6604
|
+
waveformStatus,
|
|
6605
|
+
decoded,
|
|
6606
|
+
toggle,
|
|
6607
|
+
stop,
|
|
6608
|
+
seek,
|
|
6609
|
+
skip,
|
|
6610
|
+
setPlaybackRate
|
|
6611
|
+
}),
|
|
6612
|
+
[
|
|
6613
|
+
media,
|
|
6614
|
+
src,
|
|
6615
|
+
isReady,
|
|
6616
|
+
isPlaying,
|
|
6617
|
+
currentTime,
|
|
6618
|
+
duration,
|
|
6619
|
+
playbackRate,
|
|
6620
|
+
waveformStatus,
|
|
6621
|
+
decoded,
|
|
6622
|
+
toggle,
|
|
6623
|
+
stop,
|
|
6624
|
+
seek,
|
|
6625
|
+
skip,
|
|
6626
|
+
setPlaybackRate
|
|
6627
|
+
]
|
|
6628
|
+
);
|
|
6629
|
+
const handleKeyDown = (event) => {
|
|
6630
|
+
if (event.code !== "Space") return;
|
|
6631
|
+
if (event.target.closest("button, input")) return;
|
|
6632
|
+
event.preventDefault();
|
|
6633
|
+
toggle();
|
|
6634
|
+
};
|
|
6635
|
+
return /* @__PURE__ */ jsx(MediaPlayerContext.Provider, { value, children: /* @__PURE__ */ jsxs(
|
|
6636
|
+
"section",
|
|
6637
|
+
{
|
|
6638
|
+
"aria-label": label,
|
|
6639
|
+
onKeyDown: handleKeyDown,
|
|
6640
|
+
className: cn(mediaPlayerStyles().root(), className),
|
|
6641
|
+
children: [
|
|
6642
|
+
kind === "audio" ? /* @__PURE__ */ jsx("audio", { ref: setMedia, preload: "metadata", ...src ? { src } : {} }) : null,
|
|
6643
|
+
children
|
|
6644
|
+
]
|
|
6645
|
+
}
|
|
6646
|
+
) });
|
|
6647
|
+
}
|
|
6648
|
+
function MediaStage({
|
|
6649
|
+
ref,
|
|
6650
|
+
className,
|
|
6651
|
+
children
|
|
6652
|
+
}) {
|
|
6653
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn(mediaPlayerStyles().stage(), className), children });
|
|
6654
|
+
}
|
|
6655
|
+
var mediaControlsStyles = tv({
|
|
6656
|
+
slots: {
|
|
6657
|
+
root: "shrink-0 border-t border-rule-2 px-[18px] pt-3 pb-3.5",
|
|
6658
|
+
seek: "grid grid-cols-[auto_1fr_auto] items-center gap-2.5",
|
|
6659
|
+
elapsed: "font-mono text-[12.5px] leading-none tabular-nums text-ink-2",
|
|
6660
|
+
total: "font-mono text-[12.5px] leading-none tabular-nums text-ink-4",
|
|
6661
|
+
transport: "mt-2 grid grid-cols-[1fr_auto_1fr] items-center",
|
|
6662
|
+
center: "flex items-center gap-1.5",
|
|
6663
|
+
end: "justify-self-end",
|
|
6664
|
+
text: "font-mono"
|
|
6665
|
+
}
|
|
6666
|
+
});
|
|
6667
|
+
var SKIP_SECONDS = 10;
|
|
6668
|
+
var SPEEDS = [1, 1.25, 1.5, 2];
|
|
6669
|
+
function MediaControls({ describeTime, hasSeek = true, className }) {
|
|
6670
|
+
const {
|
|
6671
|
+
isReady,
|
|
6672
|
+
isPlaying,
|
|
6673
|
+
currentTime,
|
|
6674
|
+
duration,
|
|
6675
|
+
playbackRate,
|
|
6676
|
+
toggle,
|
|
6677
|
+
stop,
|
|
6678
|
+
seek,
|
|
6679
|
+
skip,
|
|
6680
|
+
setPlaybackRate
|
|
6681
|
+
} = useMediaPlayer();
|
|
6682
|
+
const styles4 = mediaControlsStyles();
|
|
6683
|
+
const description = describeTime?.(currentTime);
|
|
6684
|
+
const valueText = `${spokenMediaTime(currentTime)} of ${spokenMediaTime(duration)}${description ? `, ${description}` : ""}`;
|
|
6685
|
+
const nextSpeed = SPEEDS[(SPEEDS.indexOf(playbackRate) + 1) % SPEEDS.length] ?? 1;
|
|
6686
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(styles4.root(), className), children: [
|
|
6687
|
+
hasSeek ? /* @__PURE__ */ jsxs("div", { className: styles4.seek(), children: [
|
|
6688
|
+
/* @__PURE__ */ jsx("span", { className: styles4.elapsed(), children: formatMediaTime(currentTime) }),
|
|
6689
|
+
/* @__PURE__ */ jsx(
|
|
6690
|
+
Slider,
|
|
6691
|
+
{
|
|
6692
|
+
"aria-label": "Seek",
|
|
6693
|
+
value: currentTime,
|
|
6694
|
+
minValue: 0,
|
|
6695
|
+
maxValue: duration || 1,
|
|
6696
|
+
step: 1,
|
|
6697
|
+
isDisabled: !isReady,
|
|
6698
|
+
valueText,
|
|
6699
|
+
onChange: seek
|
|
6700
|
+
}
|
|
6701
|
+
),
|
|
6702
|
+
/* @__PURE__ */ jsx("span", { className: styles4.total(), children: duration > 0 ? formatMediaTime(duration) : "--:--" })
|
|
6703
|
+
] }) : null,
|
|
6704
|
+
/* @__PURE__ */ jsxs("div", { className: cn(styles4.transport(), !hasSeek && "mt-0"), children: [
|
|
6705
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
6706
|
+
Button,
|
|
6707
|
+
{
|
|
6708
|
+
variant: "ghost",
|
|
6709
|
+
size: "icon-md",
|
|
6710
|
+
"aria-label": "Stop",
|
|
6711
|
+
isDisabled: !isReady,
|
|
6712
|
+
onPress: stop,
|
|
6713
|
+
children: /* @__PURE__ */ jsx(Square, {})
|
|
6714
|
+
}
|
|
6715
|
+
) }),
|
|
6716
|
+
/* @__PURE__ */ jsxs("div", { className: styles4.center(), children: [
|
|
6717
|
+
/* @__PURE__ */ jsxs(
|
|
6718
|
+
Button,
|
|
6719
|
+
{
|
|
6720
|
+
variant: "ghost",
|
|
6721
|
+
size: "sm",
|
|
6722
|
+
"aria-label": `Back ${SKIP_SECONDS} seconds`,
|
|
6723
|
+
isDisabled: !isReady,
|
|
6724
|
+
onPress: () => skip(-SKIP_SECONDS),
|
|
6725
|
+
className: styles4.text(),
|
|
6726
|
+
children: [
|
|
6727
|
+
/* @__PURE__ */ jsx(RotateCcw, {}),
|
|
6728
|
+
SKIP_SECONDS
|
|
6729
|
+
]
|
|
6730
|
+
}
|
|
6731
|
+
),
|
|
6732
|
+
/* @__PURE__ */ jsx(
|
|
6733
|
+
Button,
|
|
6734
|
+
{
|
|
6735
|
+
variant: "cta",
|
|
6736
|
+
size: "icon-lg",
|
|
6737
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
6738
|
+
isDisabled: !isReady,
|
|
6739
|
+
onPress: toggle,
|
|
6740
|
+
children: isPlaying ? /* @__PURE__ */ jsx(Pause, { fill: "currentColor" }) : /* @__PURE__ */ jsx(Play, { fill: "currentColor" })
|
|
6741
|
+
}
|
|
6742
|
+
),
|
|
6743
|
+
/* @__PURE__ */ jsxs(
|
|
6744
|
+
Button,
|
|
6745
|
+
{
|
|
6746
|
+
variant: "ghost",
|
|
6747
|
+
size: "sm",
|
|
6748
|
+
"aria-label": `Forward ${SKIP_SECONDS} seconds`,
|
|
6749
|
+
isDisabled: !isReady,
|
|
6750
|
+
onPress: () => skip(SKIP_SECONDS),
|
|
6751
|
+
className: styles4.text(),
|
|
6752
|
+
children: [
|
|
6753
|
+
SKIP_SECONDS,
|
|
6754
|
+
/* @__PURE__ */ jsx(RotateCw, {})
|
|
6755
|
+
]
|
|
6756
|
+
}
|
|
6757
|
+
)
|
|
6758
|
+
] }),
|
|
6759
|
+
/* @__PURE__ */ jsx("div", { className: styles4.end(), children: /* @__PURE__ */ jsxs(
|
|
6760
|
+
Button,
|
|
6761
|
+
{
|
|
6762
|
+
variant: "ghost",
|
|
6763
|
+
size: "sm",
|
|
6764
|
+
"aria-label": `Playback speed ${playbackRate} times`,
|
|
6765
|
+
isDisabled: !isReady,
|
|
6766
|
+
onPress: () => setPlaybackRate(nextSpeed),
|
|
6767
|
+
className: styles4.text(),
|
|
6768
|
+
children: [
|
|
6769
|
+
playbackRate,
|
|
6770
|
+
"\xD7"
|
|
6771
|
+
]
|
|
6772
|
+
}
|
|
6773
|
+
) })
|
|
6774
|
+
] })
|
|
6775
|
+
] });
|
|
6776
|
+
}
|
|
6777
|
+
var mediaMarkersStyles = tv({
|
|
6778
|
+
slots: {
|
|
6779
|
+
root: "flex shrink-0 flex-col gap-[3px]",
|
|
6780
|
+
heading: "flex min-w-0 shrink-0 items-center gap-1.5 text-[12px] leading-4 text-ink-3",
|
|
6781
|
+
dot: "size-[5px] shrink-0 rounded-pill",
|
|
6782
|
+
current: "min-w-0 truncate font-medium text-ink",
|
|
6783
|
+
count: "ml-auto shrink-0 font-mono text-[11px] text-ink-4",
|
|
6784
|
+
track: "relative h-3",
|
|
6785
|
+
marker: [
|
|
6786
|
+
"absolute top-0.5 h-2 min-w-1.5 cursor-pointer rounded-sm border p-0 outline-none",
|
|
6787
|
+
"border-[color-mix(in_oklab,var(--color-accent)_45%,var(--color-rule))]",
|
|
6788
|
+
"bg-[color-mix(in_oklab,var(--color-accent)_14%,var(--color-surface))]",
|
|
6789
|
+
"transition-colors duration-150",
|
|
6790
|
+
"hovered:border-accent hovered:bg-accent",
|
|
6791
|
+
"data-[current]:border-accent data-[current]:bg-accent",
|
|
6792
|
+
"data-[focus-visible]:shadow-[var(--shadow-focus)]",
|
|
6793
|
+
// The bar is thin; the press target isn't.
|
|
6794
|
+
"after:absolute after:inset-x-0 after:-inset-y-2 after:content-['']"
|
|
6795
|
+
]
|
|
6796
|
+
}
|
|
6797
|
+
});
|
|
6798
|
+
function currentMediaMarkers(markers, time) {
|
|
6799
|
+
return markers.filter((marker) => time >= marker.start && time < marker.end);
|
|
6800
|
+
}
|
|
6801
|
+
function MediaMarkerTrack({
|
|
6802
|
+
markers,
|
|
6803
|
+
label = "Markers",
|
|
6804
|
+
currentTime,
|
|
6805
|
+
duration,
|
|
6806
|
+
onSeek,
|
|
6807
|
+
className
|
|
6808
|
+
}) {
|
|
6809
|
+
const styles4 = mediaMarkersStyles();
|
|
6810
|
+
const current = currentMediaMarkers(markers, currentTime);
|
|
6811
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(styles4.root(), className), children: [
|
|
6812
|
+
/* @__PURE__ */ jsxs("div", { className: styles4.heading(), children: [
|
|
6813
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: styles4.dot() }),
|
|
6814
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0", children: label }),
|
|
6815
|
+
/* @__PURE__ */ jsx("span", { className: styles4.current(), children: current.map((marker) => marker.label).join(" \xB7 ") }),
|
|
6816
|
+
/* @__PURE__ */ jsx("span", { className: styles4.count(), children: markers.length })
|
|
6817
|
+
] }),
|
|
6818
|
+
/* @__PURE__ */ jsx("div", { className: styles4.track(), children: markers.map((marker) => /* @__PURE__ */ jsx(
|
|
6819
|
+
Button$1,
|
|
6820
|
+
{
|
|
6821
|
+
"data-media-marker": marker.key,
|
|
6822
|
+
"data-current": current.includes(marker) || void 0,
|
|
6823
|
+
"aria-label": `${marker.label}, at ${formatMediaTime(marker.start)}`,
|
|
6824
|
+
onPress: () => onSeek(marker.start),
|
|
6825
|
+
className: styles4.marker(),
|
|
6826
|
+
style: duration > 0 ? {
|
|
6827
|
+
left: `${marker.start / duration * 100}%`,
|
|
6828
|
+
width: `${(marker.end - marker.start) / duration * 100}%`
|
|
6829
|
+
} : { display: "none" }
|
|
6830
|
+
},
|
|
6831
|
+
marker.key
|
|
6832
|
+
)) })
|
|
6833
|
+
] });
|
|
6834
|
+
}
|
|
6835
|
+
var mediaTimelineStyles = tv({
|
|
6836
|
+
slots: {
|
|
6837
|
+
root: "flex shrink-0 flex-col gap-1 px-[18px] pt-2 pb-3",
|
|
6838
|
+
markers: "pt-1"
|
|
6839
|
+
}
|
|
6840
|
+
});
|
|
6841
|
+
function MediaTimeline({
|
|
6842
|
+
markers = [],
|
|
6843
|
+
markersLabel = "Markers",
|
|
6844
|
+
label = "Timeline",
|
|
6845
|
+
durationOverride,
|
|
6846
|
+
className
|
|
6847
|
+
}) {
|
|
6848
|
+
const { currentTime, duration: playerDuration, isReady, seek } = useMediaPlayer();
|
|
6849
|
+
const duration = durationOverride ?? playerDuration;
|
|
6850
|
+
const max = duration > 0 ? duration : 1;
|
|
6851
|
+
const styles4 = mediaTimelineStyles();
|
|
6852
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(styles4.root(), className), children: [
|
|
6853
|
+
/* @__PURE__ */ jsx(
|
|
6854
|
+
Slider,
|
|
6855
|
+
{
|
|
6856
|
+
"aria-label": label,
|
|
6857
|
+
value: Math.min(currentTime, max),
|
|
6858
|
+
minValue: 0,
|
|
6859
|
+
maxValue: max,
|
|
6860
|
+
step: 1,
|
|
6861
|
+
isDisabled: !isReady,
|
|
6862
|
+
valueText: `${spokenMediaTime(currentTime)} of ${spokenMediaTime(duration)}`,
|
|
6863
|
+
onChange: seek
|
|
6864
|
+
}
|
|
6865
|
+
),
|
|
6866
|
+
markers.length > 0 ? /* @__PURE__ */ jsx(
|
|
6867
|
+
MediaMarkerTrack,
|
|
6868
|
+
{
|
|
6869
|
+
markers,
|
|
6870
|
+
label: markersLabel,
|
|
6871
|
+
currentTime,
|
|
6872
|
+
duration,
|
|
6873
|
+
onSeek: seek,
|
|
6874
|
+
className: styles4.markers()
|
|
6875
|
+
}
|
|
6876
|
+
) : null
|
|
6877
|
+
] });
|
|
6878
|
+
}
|
|
6879
|
+
var mediaVideoStageStyles = tv({
|
|
6880
|
+
slots: {
|
|
6881
|
+
root: "items-center justify-center overflow-hidden",
|
|
6882
|
+
box: "relative shrink-0 bg-ink",
|
|
6883
|
+
video: "block size-full",
|
|
6884
|
+
overlay: "pointer-events-none absolute inset-0"
|
|
6885
|
+
}
|
|
6886
|
+
});
|
|
6887
|
+
var DEFAULT_ASPECT = 16 / 9;
|
|
6888
|
+
function fitMediaBox(width, height, aspect) {
|
|
6889
|
+
if (width <= 0 || aspect <= 0) return { width: 0, height: 0 };
|
|
6890
|
+
if (height <= 0 || width / height <= aspect) return { width, height: width / aspect };
|
|
6891
|
+
return { width: height * aspect, height };
|
|
6892
|
+
}
|
|
6893
|
+
function MediaVideoStage({ children, className }) {
|
|
6894
|
+
const { src, mediaRef } = useMediaPlayer();
|
|
6895
|
+
const styles4 = mediaVideoStageStyles();
|
|
6896
|
+
const stageRef = useRef(null);
|
|
6897
|
+
const [video, setVideo] = useState(null);
|
|
6898
|
+
const [aspect, setAspect] = useState(DEFAULT_ASPECT);
|
|
6899
|
+
const [box, setBox] = useState({ width: 0, height: 0 });
|
|
6900
|
+
const registerVideo = useCallback(
|
|
6901
|
+
(element) => {
|
|
6902
|
+
setVideo(element);
|
|
6903
|
+
mediaRef(element);
|
|
6904
|
+
},
|
|
6905
|
+
[mediaRef]
|
|
6906
|
+
);
|
|
6907
|
+
useEffect(() => {
|
|
6908
|
+
if (!video) return;
|
|
6909
|
+
const sync2 = () => {
|
|
6910
|
+
if (video.videoWidth > 0 && video.videoHeight > 0)
|
|
6911
|
+
setAspect(video.videoWidth / video.videoHeight);
|
|
6912
|
+
};
|
|
6913
|
+
sync2();
|
|
6914
|
+
video.addEventListener("loadedmetadata", sync2);
|
|
6915
|
+
video.addEventListener("resize", sync2);
|
|
6916
|
+
return () => {
|
|
6917
|
+
video.removeEventListener("loadedmetadata", sync2);
|
|
6918
|
+
video.removeEventListener("resize", sync2);
|
|
6919
|
+
};
|
|
6920
|
+
}, [video]);
|
|
6921
|
+
useEffect(() => {
|
|
6922
|
+
const stage = stageRef.current;
|
|
6923
|
+
if (!stage) return;
|
|
6924
|
+
const observer = new ResizeObserver((entries) => {
|
|
6925
|
+
const rect = entries[0]?.contentRect;
|
|
6926
|
+
if (!rect) return;
|
|
6927
|
+
const next = fitMediaBox(rect.width, rect.height, aspect);
|
|
6928
|
+
setBox(
|
|
6929
|
+
(previous) => previous.width === next.width && previous.height === next.height ? previous : next
|
|
6930
|
+
);
|
|
6931
|
+
});
|
|
6932
|
+
observer.observe(stage);
|
|
6933
|
+
return () => observer.disconnect();
|
|
6934
|
+
}, [aspect]);
|
|
6935
|
+
return /* @__PURE__ */ jsx(MediaStage, { ref: stageRef, className: cn(styles4.root(), className), children: /* @__PURE__ */ jsxs("div", { className: styles4.box(), style: { width: box.width, height: box.height }, children: [
|
|
6936
|
+
/* @__PURE__ */ jsx(
|
|
6937
|
+
"video",
|
|
6938
|
+
{
|
|
6939
|
+
ref: registerVideo,
|
|
6940
|
+
playsInline: true,
|
|
6941
|
+
preload: "metadata",
|
|
6942
|
+
className: styles4.video(),
|
|
6943
|
+
...src ? { src } : {}
|
|
6944
|
+
}
|
|
6945
|
+
),
|
|
6946
|
+
/* @__PURE__ */ jsx("div", { className: styles4.overlay(), children })
|
|
6947
|
+
] }) });
|
|
6948
|
+
}
|
|
6949
|
+
var mediaWaveformStyles = tv({
|
|
6950
|
+
slots: {
|
|
6951
|
+
root: "relative flex min-h-0 flex-1 cursor-pointer touch-none flex-col justify-center gap-2.5 px-[18px] py-3.5",
|
|
6952
|
+
lane: "flex min-h-[34px] max-h-24 flex-1 basis-0 flex-col gap-0.5",
|
|
6953
|
+
laneName: "flex min-w-0 shrink-0 items-center gap-1.5 text-[12px] leading-4 text-ink-3",
|
|
6954
|
+
laneDot: "size-[5px] shrink-0 rounded-pill",
|
|
6955
|
+
laneMeta: "ml-auto shrink-0 font-mono text-[11px] text-ink-4",
|
|
6956
|
+
bars: [
|
|
6957
|
+
"relative min-h-0 flex-1",
|
|
6958
|
+
"before:absolute before:inset-x-0 before:top-1/2 before:h-px before:bg-rule-2 before:content-['']"
|
|
6959
|
+
],
|
|
6960
|
+
canvas: "absolute inset-0",
|
|
6961
|
+
playhead: "pointer-events-none absolute inset-y-0 z-10 w-px bg-ink",
|
|
6962
|
+
hover: "pointer-events-none absolute inset-y-0 z-10 w-px bg-ink-4",
|
|
6963
|
+
chip: [
|
|
6964
|
+
"pointer-events-none absolute top-2 z-20 -translate-x-1/2 whitespace-nowrap rounded-sm bg-ink px-1.5 py-1",
|
|
6965
|
+
"font-mono text-[11px] leading-none text-surface"
|
|
6966
|
+
],
|
|
6967
|
+
status: "pointer-events-none px-[18px] pb-3 text-[12px] text-ink-3",
|
|
6968
|
+
markers: "border-t border-rule-2 pt-2"
|
|
6969
|
+
},
|
|
6970
|
+
variants: {
|
|
6971
|
+
isActive: {
|
|
6972
|
+
true: { laneName: "font-medium text-ink", laneDot: "bg-ink" }
|
|
6973
|
+
},
|
|
6974
|
+
isSeekable: {
|
|
6975
|
+
false: { root: "cursor-default" }
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
});
|
|
6979
|
+
var WHOLE_RECORDING = [{ key: "all", label: null, segments: null }];
|
|
6980
|
+
var isWithin = (segments, time) => segments?.some(([start, end]) => time >= start && time < end) ?? false;
|
|
6981
|
+
function useWaveColors() {
|
|
6982
|
+
const [colors, setColors] = useState(() => readColors());
|
|
6983
|
+
useEffect(() => {
|
|
6984
|
+
const observer = new MutationObserver(() => setColors(readColors()));
|
|
6985
|
+
observer.observe(document.documentElement, {
|
|
6986
|
+
attributes: true,
|
|
6987
|
+
attributeFilter: ["data-theme"]
|
|
6988
|
+
});
|
|
6989
|
+
return () => observer.disconnect();
|
|
6990
|
+
}, []);
|
|
6991
|
+
return colors;
|
|
6992
|
+
}
|
|
6993
|
+
function readColors() {
|
|
6994
|
+
const style = getComputedStyle(document.documentElement);
|
|
6995
|
+
return {
|
|
6996
|
+
wave: style.getPropertyValue("--color-rule-strong").trim() || "gray",
|
|
6997
|
+
progress: style.getPropertyValue("--color-ink").trim() || "black"
|
|
6998
|
+
};
|
|
6999
|
+
}
|
|
7000
|
+
var LaneBars = memo(function LaneBars2({
|
|
7001
|
+
media,
|
|
7002
|
+
peaks,
|
|
7003
|
+
duration,
|
|
7004
|
+
wave,
|
|
7005
|
+
progress,
|
|
7006
|
+
onDrawFailed
|
|
7007
|
+
}) {
|
|
7008
|
+
const containerRef = useRef(null);
|
|
7009
|
+
const instanceRef = useRef(null);
|
|
7010
|
+
const colorsRef = useRef({ wave, progress });
|
|
7011
|
+
colorsRef.current = { wave, progress };
|
|
7012
|
+
useEffect(() => {
|
|
7013
|
+
const container = containerRef.current;
|
|
7014
|
+
if (!container) return;
|
|
7015
|
+
let isCancelled = false;
|
|
7016
|
+
let instance = null;
|
|
7017
|
+
let observer = null;
|
|
7018
|
+
import('wavesurfer.js').then(({ default: WaveSurferClass }) => {
|
|
7019
|
+
if (isCancelled) return;
|
|
7020
|
+
instance = WaveSurferClass.create({
|
|
7021
|
+
container,
|
|
7022
|
+
media,
|
|
7023
|
+
peaks: [peaks],
|
|
7024
|
+
duration,
|
|
7025
|
+
height: container.clientHeight || 1,
|
|
7026
|
+
barWidth: 2,
|
|
7027
|
+
barGap: 1,
|
|
7028
|
+
barRadius: 1,
|
|
7029
|
+
cursorWidth: 0,
|
|
7030
|
+
interact: false,
|
|
7031
|
+
normalize: false,
|
|
7032
|
+
autoScroll: false,
|
|
7033
|
+
hideScrollbar: true,
|
|
7034
|
+
// A new instance otherwise resets the shared element to its own default.
|
|
7035
|
+
audioRate: media.playbackRate,
|
|
7036
|
+
waveColor: colorsRef.current.wave,
|
|
7037
|
+
progressColor: colorsRef.current.progress
|
|
7038
|
+
});
|
|
7039
|
+
instanceRef.current = instance;
|
|
7040
|
+
let lastHeight = container.clientHeight;
|
|
7041
|
+
observer = new ResizeObserver(() => {
|
|
7042
|
+
const height = container.clientHeight;
|
|
7043
|
+
if (height > 0 && height !== lastHeight) {
|
|
7044
|
+
lastHeight = height;
|
|
7045
|
+
instance?.setOptions({ height });
|
|
7046
|
+
}
|
|
7047
|
+
});
|
|
7048
|
+
observer.observe(container);
|
|
7049
|
+
}).catch(() => {
|
|
7050
|
+
if (!isCancelled) onDrawFailed();
|
|
7051
|
+
});
|
|
7052
|
+
return () => {
|
|
7053
|
+
isCancelled = true;
|
|
7054
|
+
observer?.disconnect();
|
|
7055
|
+
instance?.destroy();
|
|
7056
|
+
instanceRef.current = null;
|
|
7057
|
+
};
|
|
7058
|
+
}, [media, peaks, duration, onDrawFailed]);
|
|
7059
|
+
useEffect(() => {
|
|
7060
|
+
instanceRef.current?.setOptions({ waveColor: wave, progressColor: progress });
|
|
7061
|
+
}, [wave, progress]);
|
|
7062
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: mediaWaveformStyles().canvas(), "aria-hidden": true });
|
|
7063
|
+
});
|
|
7064
|
+
function MediaWaveform({
|
|
7065
|
+
lanes: lanesProp,
|
|
7066
|
+
markers = [],
|
|
7067
|
+
markersLabel = "Markers",
|
|
7068
|
+
className
|
|
7069
|
+
}) {
|
|
7070
|
+
const { media, decoded, duration, currentTime, waveformStatus, isReady, isPlaying, seek } = useMediaPlayer();
|
|
7071
|
+
const lanes = lanesProp && lanesProp.length > 0 ? lanesProp : WHOLE_RECORDING;
|
|
7072
|
+
const colors = useWaveColors();
|
|
7073
|
+
const styles4 = mediaWaveformStyles({ isSeekable: isReady });
|
|
7074
|
+
const rootRef = useRef(null);
|
|
7075
|
+
const playheadRef = useRef(null);
|
|
7076
|
+
const [hover, setHover] = useState(null);
|
|
7077
|
+
const [isDrawFailed, setIsDrawFailed] = useState(false);
|
|
7078
|
+
const handleDrawFailed = useCallback(() => setIsDrawFailed(true), []);
|
|
7079
|
+
const lanePeaks = useMemo(
|
|
7080
|
+
() => lanes.map(
|
|
7081
|
+
(lane) => decoded && lane.segments ? maskPeaks(decoded.peaks, decoded.duration, lane.segments) : decoded?.peaks ?? null
|
|
7082
|
+
),
|
|
7083
|
+
[lanes, decoded]
|
|
7084
|
+
);
|
|
7085
|
+
useEffect(() => {
|
|
7086
|
+
const playhead = playheadRef.current;
|
|
7087
|
+
if (!media || !playhead) return;
|
|
7088
|
+
let frame = 0;
|
|
7089
|
+
const place = () => {
|
|
7090
|
+
const position = duration > 0 ? Math.min(1, media.currentTime / duration) : 0;
|
|
7091
|
+
playhead.style.left = `calc(18px + (100% - 36px) * ${position})`;
|
|
7092
|
+
playhead.style.visibility = position > 0 ? "visible" : "hidden";
|
|
7093
|
+
};
|
|
7094
|
+
const loop = () => {
|
|
7095
|
+
place();
|
|
7096
|
+
frame = requestAnimationFrame(loop);
|
|
7097
|
+
};
|
|
7098
|
+
place();
|
|
7099
|
+
if (isPlaying) frame = requestAnimationFrame(loop);
|
|
7100
|
+
media.addEventListener("seeked", place);
|
|
7101
|
+
return () => {
|
|
7102
|
+
cancelAnimationFrame(frame);
|
|
7103
|
+
media.removeEventListener("seeked", place);
|
|
7104
|
+
};
|
|
7105
|
+
}, [media, duration, isPlaying]);
|
|
7106
|
+
const timeAt = (clientX) => {
|
|
7107
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
7108
|
+
if (!rect || duration <= 0) return 0;
|
|
7109
|
+
return (Math.max(0, Math.min(1, (clientX - rect.left - 18) / (rect.width - 36))) || 0) * duration;
|
|
7110
|
+
};
|
|
7111
|
+
const handlePointerDown = (event) => {
|
|
7112
|
+
if (!isReady || event.target.closest("[data-media-marker]")) return;
|
|
7113
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
7114
|
+
seek(timeAt(event.clientX));
|
|
7115
|
+
};
|
|
7116
|
+
const handlePointerMove = (event) => {
|
|
7117
|
+
if (!isReady) return;
|
|
7118
|
+
const time = timeAt(event.clientX);
|
|
7119
|
+
if (event.buttons > 0 && event.currentTarget.hasPointerCapture(event.pointerId)) seek(time);
|
|
7120
|
+
const target = event.target;
|
|
7121
|
+
const markerKey = target.closest("[data-media-marker]")?.dataset.mediaMarker;
|
|
7122
|
+
const laneKey = target.closest("[data-media-lane]")?.dataset.mediaLane;
|
|
7123
|
+
const marker = markers.find((entry) => entry.key === markerKey);
|
|
7124
|
+
const lane = lanes.find((entry) => entry.key === laneKey);
|
|
7125
|
+
const name = marker?.label ?? (lane?.label && isWithin(lane.segments, time) ? lane.label : null);
|
|
7126
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
7127
|
+
setHover({
|
|
7128
|
+
x: event.clientX - rect.left,
|
|
7129
|
+
text: name ? `${name} \xB7 ${formatMediaTime(time)}` : formatMediaTime(time)
|
|
7130
|
+
});
|
|
7131
|
+
};
|
|
7132
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7133
|
+
/* @__PURE__ */ jsxs(
|
|
7134
|
+
"div",
|
|
7135
|
+
{
|
|
7136
|
+
ref: rootRef,
|
|
7137
|
+
onPointerDown: handlePointerDown,
|
|
7138
|
+
onPointerMove: handlePointerMove,
|
|
7139
|
+
onPointerLeave: () => setHover(null),
|
|
7140
|
+
className: cn(styles4.root(), className),
|
|
7141
|
+
children: [
|
|
7142
|
+
lanes.map((lane, index) => {
|
|
7143
|
+
const isActive = lane.segments !== null && isWithin(lane.segments, currentTime);
|
|
7144
|
+
const peaks = lanePeaks[index];
|
|
7145
|
+
const laneStyles = mediaWaveformStyles({ isActive });
|
|
7146
|
+
return /* @__PURE__ */ jsxs("div", { "data-media-lane": lane.key, className: styles4.lane(), children: [
|
|
7147
|
+
lane.label !== null ? /* @__PURE__ */ jsxs("div", { className: laneStyles.laneName(), "data-active": isActive || void 0, children: [
|
|
7148
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: laneStyles.laneDot() }),
|
|
7149
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: lane.label }),
|
|
7150
|
+
lane.meta ? /* @__PURE__ */ jsx("span", { className: styles4.laneMeta(), children: lane.meta }) : null
|
|
7151
|
+
] }) : null,
|
|
7152
|
+
/* @__PURE__ */ jsx("div", { className: styles4.bars(), children: media && peaks && decoded ? /* @__PURE__ */ jsx(
|
|
7153
|
+
LaneBars,
|
|
7154
|
+
{
|
|
7155
|
+
media,
|
|
7156
|
+
peaks,
|
|
7157
|
+
duration: decoded.duration,
|
|
7158
|
+
wave: colors.wave,
|
|
7159
|
+
progress: colors.progress,
|
|
7160
|
+
onDrawFailed: handleDrawFailed
|
|
7161
|
+
}
|
|
7162
|
+
) : null })
|
|
7163
|
+
] }, lane.key);
|
|
7164
|
+
}),
|
|
7165
|
+
markers.length > 0 ? /* @__PURE__ */ jsx(
|
|
7166
|
+
MediaMarkerTrack,
|
|
7167
|
+
{
|
|
7168
|
+
markers,
|
|
7169
|
+
label: markersLabel,
|
|
7170
|
+
currentTime,
|
|
7171
|
+
duration,
|
|
7172
|
+
onSeek: seek,
|
|
7173
|
+
className: styles4.markers()
|
|
7174
|
+
}
|
|
7175
|
+
) : null,
|
|
7176
|
+
/* @__PURE__ */ jsx("div", { ref: playheadRef, className: styles4.playhead() }),
|
|
7177
|
+
hover ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7178
|
+
/* @__PURE__ */ jsx("div", { className: styles4.hover(), style: { left: hover.x } }),
|
|
7179
|
+
/* @__PURE__ */ jsx(
|
|
7180
|
+
"span",
|
|
7181
|
+
{
|
|
7182
|
+
className: styles4.chip(),
|
|
7183
|
+
style: { left: `clamp(70px, ${hover.x}px, calc(100% - 70px))` },
|
|
7184
|
+
children: hover.text
|
|
7185
|
+
}
|
|
7186
|
+
)
|
|
7187
|
+
] }) : null
|
|
7188
|
+
]
|
|
7189
|
+
}
|
|
7190
|
+
),
|
|
7191
|
+
waveformStatus === "decoding" ? /* @__PURE__ */ jsx("p", { className: styles4.status(), children: "Drawing waveform" }) : null,
|
|
7192
|
+
waveformStatus === "unavailable" || isDrawFailed ? /* @__PURE__ */ jsx("p", { className: styles4.status(), children: "Waveform isn\u2019t available. Use the slider to seek." }) : null
|
|
7193
|
+
] });
|
|
7194
|
+
}
|
|
6235
7195
|
var MenuTrigger = MenuTrigger$1;
|
|
6236
7196
|
var SubmenuTrigger = SubmenuTrigger$1;
|
|
6237
7197
|
function MenuPopover({ className, offset = 4, placement = "bottom start", ...props }) {
|
|
@@ -9387,6 +10347,6 @@ function ToastRegion({ queue, className }) {
|
|
|
9387
10347
|
);
|
|
9388
10348
|
}
|
|
9389
10349
|
|
|
9390
|
-
export { ATTRIBUTE_TYPES, ATTRIBUTE_TYPE_ICONS, AttachmentChip, AttributePicker, AttributeType, AttributeTypeIcon, AvailabilityCalendar, Avatar, AvatarGroup, Badge, BadgeAction, BadgeGroup, BadgeMultiSelect, BooleanCell, Breadcrumbs, COLUMN_DRAG_KIND, CONVERSATION_BRIEF_OUTCOME_LABEL, Card, CardBody, CardContent, CardEyebrow, CardFeatureTitle, CardFooter, CardHeader, CardTitle, ChannelIcon, Checkbox, CheckboxGroup, ChipValue, ColorInput, Combobox, Command, CommandHint, ConversationBriefCard, ConversationBriefPreview, ConversationBriefReview, CurrencyInput, DRAFT_OUTCOME_LABEL, DataTable, DataTableEmpty, DataTableError, DataTableSkeleton, DateCell, DatePicker, DateTimeCell, DateTimePicker, DraftMessageCard, DraftMessageComposer, DraftMessageReview, EmptyState, ErrorAnimation, FIELD_LABEL_SEPARATOR, FieldCaret, FileField, FileViewer, FileViewerFallbackCard, FilterRow, FilterValueInput, GlowFrame, IconPicker, ImageAttachment, ImageLightbox, Input, Kbd, LinkCell, MAX_COMPOSER_ATTACHMENT_BYTES, Menu, MenuItem, MenuPopover, MenuTrigger, MessageComposer, Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, MultiSelect, NavGroup, NavItem, NavSection, OPERATORS, OperatorPicker, Orb, PROTECTED_COMBOS, Popover, PopoverContent, PopoverPanelBody, PopoverPanelFooter, PopoverPanelHeader, PressableCard, ProgressBar, ProgressRing, Radio, RadioGroup, RecipientSelect, RecordFilterBuilderPanel, RecordFilterButton, RecordFilterChips, RecordFilterEditor, RecordUpdate, RecordUpdateErrors, RecordUpdateFooter, RecordUpdateRow, RecordUpdateRows, RecordUpdateSummary, RenderChipItemProvider, RenderValueInputProvider, SELECTION_COLUMN_ID, SegmentedControl, Select, Separator, Stepper, StepperStep, SubmenuTrigger, SuccessAnimation, Switch, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableHeaderSpacer, TableRow, TableScroller, Tabs, TagInput, TextShimmer, Textarea, TimeField, TimeSlotList, ToastRegion, Tooltip, TooltipTrigger, TruncateCell, __resetDraftMessageActions, __resetDraftMessageOutcomes, addLeaf as addFilterLeaf, addPendingLeaf, addSubgroup, arityOf, attachmentChipStyles, availabilityCalendarStyles, avatarGroupStyles, avatarStyles, badgeGroupOverflowStyles, badgeGroupStyles, badgeStyles, cardStyles2 as cardStyles, channelIcon, contactPhoneNumbers, conversationBriefCardStyles, conversationBriefOutcomeFor, countLeaves, createConversationBriefClient, createDraftMessageClient, createToastQueue, defaultValueFor, draftMessageCardStyles, draftMessageComposerStyles, draftOutcomeFor, emptyStateStyles, fieldControlStyles, fieldErrorStyles, fieldHintStyles, fieldLabelStyles, fileViewerFallbackCardStyles, fileViewerStyles, fitBadgeCount, formatFileSize, formatValue, getPlatform, glowFrameStyles, iconForContentType, imageAttachmentStyles, imageLightboxStyles, isColumnDragData, isDialableConversationBrief, isDraftReviewOutcome, isEditableTarget, isPreviewableImageName, joinFieldLabel, makeActionsColumn, messageComposerStyles, namesOf, navItemStyles, normalizeHexColor, operatorById, operatorsForType, parseCombo, progressBarStyles, progressRingStyles, publishDraftMessageOutcome, rebaseRowOnFieldChange, rebaseRowOnOperatorChange, recordUpdateRowStyles, recordUpdateStyles, registerDraftMessageActions, removeLeaf, removeSubgroup, replaceLeaf, resolveLucideIcon, resolveLucideIconName, segmentedControlStyles, setJoiner, stepperStyles, subscribeDraftMessageOutcome, summaryFor, tableCellStyles, tableHeaderCellStyles, tabsStyles, terminalKindFor, textShimmerStyles, timeSlotListStyles, toastStyles, updateLeaf, updateSubgroup, useActiveCommands, useAttributeTypeIcon, useCommand, useDiscoveryActive, useDraftMessageActions, useDraftMessageOutcome, useEscapeKey, useInfiniteScrollSentinel, useRenderChipItem, useRenderValueInput, useShowDetails, viewerKindForContentType, wrapLeafInGroup };
|
|
10350
|
+
export { ATTRIBUTE_TYPES, ATTRIBUTE_TYPE_ICONS, AttachmentChip, AttributePicker, AttributeType, AttributeTypeIcon, AvailabilityCalendar, Avatar, AvatarGroup, Badge, BadgeAction, BadgeGroup, BadgeMultiSelect, BooleanCell, Breadcrumbs, COLUMN_DRAG_KIND, CONVERSATION_BRIEF_OUTCOME_LABEL, Card, CardBody, CardContent, CardEyebrow, CardFeatureTitle, CardFooter, CardHeader, CardTitle, ChannelIcon, Checkbox, CheckboxGroup, ChipValue, ColorInput, Combobox, Command, CommandHint, ConversationBriefCard, ConversationBriefPreview, ConversationBriefReview, CurrencyInput, DRAFT_OUTCOME_LABEL, DataTable, DataTableEmpty, DataTableError, DataTableSkeleton, DateCell, DatePicker, DateTimeCell, DateTimePicker, DraftMessageCard, DraftMessageComposer, DraftMessageReview, EmptyState, ErrorAnimation, FIELD_LABEL_SEPARATOR, FieldCaret, FileField, FileViewer, FileViewerFallbackCard, FilterRow, FilterValueInput, FrameStrip, GlowFrame, IconPicker, ImageAttachment, ImageLightbox, Input, Kbd, LinkCell, MAX_COMPOSER_ATTACHMENT_BYTES, MAX_DECODE_BYTES, MediaControls, MediaMarkerTrack, MediaPlayer, MediaStage, MediaTimeline, MediaVideoStage, MediaWaveform, Menu, MenuItem, MenuPopover, MenuTrigger, MessageComposer, Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, MultiSelect, NavGroup, NavItem, NavSection, OPERATORS, OperatorPicker, Orb, PROTECTED_COMBOS, Popover, PopoverContent, PopoverPanelBody, PopoverPanelFooter, PopoverPanelHeader, PressableCard, ProgressBar, ProgressRing, Radio, RadioGroup, RecipientSelect, RecordFilterBuilderPanel, RecordFilterButton, RecordFilterChips, RecordFilterEditor, RecordUpdate, RecordUpdateErrors, RecordUpdateFooter, RecordUpdateRow, RecordUpdateRows, RecordUpdateSummary, RenderChipItemProvider, RenderValueInputProvider, SELECTION_COLUMN_ID, SegmentedControl, Select, Separator, Slider, Stepper, StepperStep, SubmenuTrigger, SuccessAnimation, Switch, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableHeaderSpacer, TableRow, TableScroller, Tabs, TagInput, TextShimmer, Textarea, TimeField, TimeSlotList, ToastRegion, Tooltip, TooltipTrigger, TruncateCell, __resetDraftMessageActions, __resetDraftMessageOutcomes, addLeaf as addFilterLeaf, addPendingLeaf, addSubgroup, arityOf, attachmentChipStyles, availabilityCalendarStyles, avatarGroupStyles, avatarStyles, badgeGroupOverflowStyles, badgeGroupStyles, badgeStyles, cardStyles2 as cardStyles, channelIcon, contactPhoneNumbers, conversationBriefCardStyles, conversationBriefOutcomeFor, countLeaves, createConversationBriefClient, createDraftMessageClient, createToastQueue, currentMediaMarkers, decodePeaks, defaultValueFor, draftMessageCardStyles, draftMessageComposerStyles, draftOutcomeFor, emptyStateStyles, fieldControlStyles, fieldErrorStyles, fieldHintStyles, fieldLabelStyles, fileViewerFallbackCardStyles, fileViewerStyles, fitBadgeCount, fitMediaBox, formatFileSize, formatMediaTime, formatValue, frameStripStyles, getPlatform, glowFrameStyles, iconForContentType, imageAttachmentStyles, imageLightboxStyles, isColumnDragData, isDialableConversationBrief, isDraftReviewOutcome, isEditableTarget, isPreviewableImageName, joinFieldLabel, makeActionsColumn, maskPeaks, mediaControlsStyles, mediaMarkersStyles, mediaPlayerStyles, mediaTimelineStyles, mediaVideoStageStyles, mediaWaveformStyles, messageComposerStyles, namesOf, navItemStyles, normalizeHexColor, operatorById, operatorsForType, parseCombo, peaksFromChannels, progressBarStyles, progressRingStyles, publishDraftMessageOutcome, rebaseRowOnFieldChange, rebaseRowOnOperatorChange, recordUpdateRowStyles, recordUpdateStyles, registerDraftMessageActions, removeLeaf, removeSubgroup, replaceLeaf, resolveLucideIcon, resolveLucideIconName, segmentedControlStyles, setJoiner, sliderStyles, spokenMediaTime, stepperStyles, subscribeDraftMessageOutcome, summaryFor, tableCellStyles, tableHeaderCellStyles, tabsStyles, terminalKindFor, textShimmerStyles, timeSlotListStyles, toastStyles, updateLeaf, updateSubgroup, useActiveCommands, useAttributeTypeIcon, useCommand, useDiscoveryActive, useDraftMessageActions, useDraftMessageOutcome, useEscapeKey, useInfiniteScrollSentinel, useMediaPlayer, useRenderChipItem, useRenderValueInput, useShowDetails, viewerKindForContentType, wrapLeafInGroup };
|
|
9391
10351
|
//# sourceMappingURL=index.js.map
|
|
9392
10352
|
//# sourceMappingURL=index.js.map
|