@theoremjs/react 0.0.0-stage → 0.3.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/LICENSE +21 -0
- package/README.md +246 -2
- package/client/attachment-hover-preview.d.ts +11 -0
- package/client/attachment-hover-preview.js +36 -0
- package/client/audio-level.d.ts +5 -0
- package/client/audio-level.js +24 -0
- package/client/composer-attachments.d.ts +30 -0
- package/client/composer-attachments.js +33 -0
- package/client/composer-drawer.d.ts +19 -0
- package/client/composer-drawer.js +15 -0
- package/client/composer-hints.d.ts +25 -0
- package/client/composer-hints.js +20 -0
- package/client/composer-primary.d.ts +16 -0
- package/client/composer-primary.js +25 -0
- package/client/decision-transport.d.ts +48 -0
- package/client/decision-transport.js +102 -0
- package/client/decode-composer-draft.d.ts +11 -0
- package/client/decode-composer-draft.js +12 -0
- package/client/encode-composer-draft.d.ts +9 -0
- package/client/encode-composer-draft.js +34 -0
- package/client/encode-files.d.ts +18 -0
- package/client/encode-files.js +54 -0
- package/client/failure.d.ts +32 -0
- package/client/failure.js +34 -0
- package/client/generation-selection.d.ts +15 -0
- package/client/generation-selection.js +24 -0
- package/client/host-call.d.ts +51 -0
- package/client/host-call.js +42 -0
- package/client/host-transport.d.ts +68 -0
- package/client/host-transport.js +74 -0
- package/client/image-output.d.ts +6 -0
- package/client/image-output.js +13 -0
- package/client/index.d.ts +20 -0
- package/client/index.js +18 -0
- package/client/ink-waveform.d.ts +17 -0
- package/client/ink-waveform.js +69 -0
- package/client/live/apply-live-turn-tool-event.d.ts +14 -0
- package/client/live/apply-live-turn-tool-event.js +39 -0
- package/client/live/live-captions.d.ts +23 -0
- package/client/live/live-captions.js +70 -0
- package/client/live/live-mic-forward.d.ts +29 -0
- package/client/live/live-mic-forward.js +37 -0
- package/client/live/live-state.d.ts +11 -0
- package/client/live/live-state.js +20 -0
- package/client/live/live-tool.d.ts +11 -0
- package/client/live/live-tool.js +1 -0
- package/client/live/live-video.d.ts +10 -0
- package/client/live/live-video.js +71 -0
- package/client/live/run-live-tool-call.d.ts +17 -0
- package/client/live/run-live-tool-call.js +32 -0
- package/client/live-client.d.ts +141 -0
- package/client/live-client.js +638 -0
- package/client/live-errors.d.ts +2 -0
- package/client/live-errors.js +9 -0
- package/client/live-messages.d.ts +110 -0
- package/client/live-messages.js +67 -0
- package/client/mic-capture.d.ts +4 -0
- package/client/mic-capture.js +6 -0
- package/client/oauth-popup.d.ts +26 -0
- package/client/oauth-popup.js +30 -0
- package/client/pcm-downsample.d.ts +4 -0
- package/client/pcm-downsample.js +45 -0
- package/client/run-commit.d.ts +61 -0
- package/client/run-commit.js +124 -0
- package/client/run-session.d.ts +80 -0
- package/client/run-session.js +215 -0
- package/client/schema-fields.d.ts +63 -0
- package/client/schema-fields.js +178 -0
- package/client/shaped-data.d.ts +118 -0
- package/client/shaped-data.js +314 -0
- package/client/source-citations.d.ts +13 -0
- package/client/source-citations.js +56 -0
- package/client/state-fields.d.ts +16 -0
- package/client/state-fields.js +44 -0
- package/client/tool-result.d.ts +78 -0
- package/client/tool-result.js +275 -0
- package/client/tool-resume.d.ts +33 -0
- package/client/tool-resume.js +11 -0
- package/client/trace-feed.d.ts +13 -0
- package/client/trace-feed.js +18 -0
- package/client/trace-story.d.ts +163 -0
- package/client/trace-story.js +416 -0
- package/client/trace-view.d.ts +130 -0
- package/client/trace-view.js +293 -0
- package/client/transcript-groups.d.ts +114 -0
- package/client/transcript-groups.js +167 -0
- package/client/transcript-scroll.d.ts +7 -0
- package/client/transcript-scroll.js +6 -0
- package/client/transport.d.ts +176 -0
- package/client/transport.js +256 -0
- package/client/turn-client.d.ts +35 -0
- package/client/turn-client.js +93 -0
- package/client/voice-label.d.ts +2 -0
- package/client/voice-label.js +15 -0
- package/client/voice-recorder.d.ts +27 -0
- package/client/voice-recorder.js +165 -0
- package/client/walk-away.d.ts +34 -0
- package/client/walk-away.js +48 -0
- package/client/wire-line.d.ts +56 -0
- package/client/wire-line.js +90 -0
- package/client/worklets/mic-capture.js +16 -0
- package/components/InkWaveform.d.ts +10 -0
- package/components/InkWaveform.js +108 -0
- package/components/live/use-live-runner-controls.d.ts +48 -0
- package/components/live/use-live-runner-controls.js +100 -0
- package/components/live/use-live-runner-model.d.ts +45 -0
- package/components/live/use-live-runner-model.js +175 -0
- package/components/live/use-live-runner-ui.d.ts +65 -0
- package/components/live/use-live-runner-ui.js +159 -0
- package/components/live/use-live-session-client.d.ts +41 -0
- package/components/live/use-live-session-client.js +123 -0
- package/components/use-composer-voice.d.ts +28 -0
- package/components/use-composer-voice.js +90 -0
- package/components/use-editor-selection.d.ts +3 -0
- package/components/use-editor-selection.js +16 -0
- package/components/use-voice-playback.d.ts +16 -0
- package/components/use-voice-playback.js +68 -0
- package/hooks/use-described.d.ts +8 -0
- package/hooks/use-described.js +23 -0
- package/hooks/use-theorem-chat-actions.d.ts +75 -0
- package/hooks/use-theorem-chat-actions.js +265 -0
- package/hooks/use-theorem-chat-state.d.ts +66 -0
- package/hooks/use-theorem-chat-state.js +118 -0
- package/hooks/use-theorem-chat.d.ts +63 -0
- package/hooks/use-theorem-chat.js +340 -0
- package/hooks/use-theorem-decision.d.ts +23 -0
- package/hooks/use-theorem-decision.js +75 -0
- package/hooks/use-theorem-host.d.ts +44 -0
- package/hooks/use-theorem-host.js +117 -0
- package/hooks/use-theorem-interface.d.ts +19 -0
- package/hooks/use-theorem-interface.js +25 -0
- package/hooks/use-trace-records.d.ts +4 -0
- package/hooks/use-trace-records.js +7 -0
- package/index.d.ts +14 -0
- package/index.js +14 -0
- package/live.d.ts +8 -0
- package/live.js +10 -0
- package/package.json +73 -4
- package/server/credential-store.d.ts +24 -0
- package/server/credential-store.js +14 -0
- package/server/decision-handler.d.ts +34 -0
- package/server/decision-handler.js +55 -0
- package/server/handler.d.ts +114 -0
- package/server/handler.js +568 -0
- package/server/json-response.d.ts +2 -0
- package/server/json-response.js +7 -0
- package/server/mod.d.ts +16 -0
- package/server/mod.js +15 -0
- package/server/request-check.d.ts +16 -0
- package/server/request-check.js +34 -0
- package/server/session-store.d.ts +74 -0
- package/server/session-store.js +49 -0
- package/server/steer-inbox.d.ts +35 -0
- package/server/steer-inbox.js +52 -0
- package/server/walk-away.d.ts +22 -0
- package/server/walk-away.js +41 -0
- package/styles/ink-controls.css +134 -0
- package/ui/ChatComposerBar.d.ts +39 -0
- package/ui/ChatComposerBar.js +251 -0
- package/ui/ChatTranscript.d.ts +30 -0
- package/ui/ChatTranscript.js +474 -0
- package/ui/ConsoleFrame.d.ts +47 -0
- package/ui/ConsoleFrame.js +46 -0
- package/ui/DecisionAnswers.d.ts +15 -0
- package/ui/DecisionAnswers.js +102 -0
- package/ui/LiveRunner.d.ts +28 -0
- package/ui/LiveRunner.js +193 -0
- package/ui/SchemaFields.d.ts +10 -0
- package/ui/SchemaFields.js +122 -0
- package/ui/ShapedData.d.ts +11 -0
- package/ui/ShapedData.js +151 -0
- package/ui/SidePanel.d.ts +57 -0
- package/ui/SidePanel.js +50 -0
- package/ui/StateFields.d.ts +36 -0
- package/ui/StateFields.js +96 -0
- package/ui/TheoremChat.d.ts +71 -0
- package/ui/TheoremChat.js +146 -0
- package/ui/TheoremDecision.d.ts +38 -0
- package/ui/TheoremDecision.js +87 -0
- package/ui/TheoremHost.d.ts +38 -0
- package/ui/TheoremHost.js +150 -0
- package/ui/ToolGateCard.d.ts +28 -0
- package/ui/ToolGateCard.js +100 -0
- package/ui/ToolResult.d.ts +10 -0
- package/ui/ToolResult.js +60 -0
- package/ui/ToolResultCharts.d.ts +5 -0
- package/ui/ToolResultCharts.js +86 -0
- package/ui/TraceCharts.d.ts +13 -0
- package/ui/TraceCharts.js +235 -0
- package/ui/TraceGuardrails.d.ts +10 -0
- package/ui/TraceGuardrails.js +56 -0
- package/ui/TraceInspector.d.ts +6 -0
- package/ui/TraceInspector.js +189 -0
- package/ui/TraceInspectorPanel.d.ts +24 -0
- package/ui/TraceInspectorPanel.js +57 -0
- package/ui/TraceOverview.d.ts +34 -0
- package/ui/TraceOverview.js +96 -0
- package/ui/TraceSpanDetail.d.ts +10 -0
- package/ui/TraceSpanDetail.js +188 -0
- package/ui/TraceStory.d.ts +20 -0
- package/ui/TraceStory.js +107 -0
- package/ui/TraceValues.d.ts +36 -0
- package/ui/TraceValues.js +113 -0
- package/ui/TraceWaterfall.d.ts +13 -0
- package/ui/TraceWaterfall.js +132 -0
- package/ui/VoiceNote.d.ts +12 -0
- package/ui/VoiceNote.js +28 -0
- package/ui/built/theme.css +774 -0
- package/ui/built/theorem.d.ts +13 -0
- package/ui/built/theorem.js +631 -0
- package/ui/built/theorem.variants.d.ts +16 -0
- package/ui/disclosure-motion.d.ts +6 -0
- package/ui/disclosure-motion.js +163 -0
- package/ui/icons.d.ts +4 -0
- package/ui/icons.js +37 -0
- package/ui/index.d.ts +25 -0
- package/ui/index.js +29 -0
- package/ui/labels-provider.d.ts +16 -0
- package/ui/labels-provider.js +61 -0
- package/ui/labels.d.ts +1153 -0
- package/ui/labels.js +603 -0
- package/ui/theme.d.ts +10 -0
- package/ui/theme.js +13 -0
- package/ui/theorem-theme.d.ts +10 -0
- package/ui/theorem-theme.js +83 -0
- package/ui/trace-palette.d.ts +24 -0
- package/ui/trace-palette.js +24 -0
- package/ui/trace-patterns.d.ts +32 -0
- package/ui/trace-patterns.js +44 -0
- package/ui/transcript-copy-text.d.ts +4 -0
- package/ui/transcript-copy-text.js +39 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@astryxdesign/core/Button';
|
|
3
|
+
import { HStack } from '@astryxdesign/core/HStack';
|
|
4
|
+
import { Icon } from '@astryxdesign/core/Icon';
|
|
5
|
+
import { Text } from '@astryxdesign/core/Text';
|
|
6
|
+
import { VStack } from '@astryxdesign/core/VStack';
|
|
7
|
+
import { IconZoomOut } from '@tabler/icons-react';
|
|
8
|
+
import { useMemo, useRef, useState } from 'react';
|
|
9
|
+
import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, ReferenceArea, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts';
|
|
10
|
+
import { traceActivity, traceActor, traceBars, traceOutcome } from "../client/trace-story.js";
|
|
11
|
+
import { ChartFrame, ChartTip, FIRST_WIDTH_PX } from "./TraceOverview.js";
|
|
12
|
+
import { TRACE_HUE } from "./trace-palette.js";
|
|
13
|
+
import { ACTOR_FILL, TRACE_RADIUS, traceFill } from "./trace-patterns.js";
|
|
14
|
+
import { useTraceFormat } from "./TraceValues.js";
|
|
15
|
+
/** Slices in the activity strip. */
|
|
16
|
+
const BUCKETS = 120;
|
|
17
|
+
/** Height of one span's row, in pixels. */
|
|
18
|
+
const ROW_PX = 22;
|
|
19
|
+
/** Height of the time axis under the rows. */
|
|
20
|
+
const AXIS_PX = 24;
|
|
21
|
+
/** Height of the activity strip. */
|
|
22
|
+
const STRIP_PX = 36;
|
|
23
|
+
/** Room right of the plot, so the last tick's label fits. */
|
|
24
|
+
const PLOT_RIGHT_PX = 4;
|
|
25
|
+
/** Width of the name column, in pixels. */
|
|
26
|
+
const NAME_PX = 132;
|
|
27
|
+
/** Indent per level of nesting in the name column. */
|
|
28
|
+
const INDENT_PX = 8;
|
|
29
|
+
function barHatch(node) {
|
|
30
|
+
return ACTOR_FILL[traceActor(node)];
|
|
31
|
+
}
|
|
32
|
+
function BarTip({ active, payload }) {
|
|
33
|
+
const format = useTraceFormat();
|
|
34
|
+
const row = payload?.[0]?.payload;
|
|
35
|
+
if (!active || !row)
|
|
36
|
+
return null;
|
|
37
|
+
const { node, from } = row.bar;
|
|
38
|
+
const outcome = traceOutcome(node);
|
|
39
|
+
const cost = node.span.attributes['theorem.usage.cost_usd'];
|
|
40
|
+
return (_jsx(ChartTip, { children: _jsxs(VStack, { gap: 0, children: [_jsx(Text, { weight: "medium", children: row.name }), _jsx(Text, { type: "supporting", color: "secondary", children: node.meta.label }), _jsx(Text, { type: "supporting", hasTabularNumbers: true, children: [
|
|
41
|
+
format.duration(node.durationMs),
|
|
42
|
+
format.t('@theorem.panel.trace.offset', { duration: format.duration(from) }),
|
|
43
|
+
...(typeof cost === 'number' ? [format.usd(cost)] : []),
|
|
44
|
+
].join(format.t('@theorem.panel.trace.separator')) }), outcome ? (_jsx(Text, { type: "supporting", children: _jsx("span", { style: { color: outcome.tone === 'error' ? TRACE_HUE.oxblood : 'var(--color-text-secondary)' }, children: outcome.label }) })) : null] }) }));
|
|
45
|
+
}
|
|
46
|
+
/** A row's name, from the chart's left edge, set in by its depth and cut to the column. */
|
|
47
|
+
function NameTick({ y: rawY, payload, rows, }) {
|
|
48
|
+
const row = typeof payload?.value === 'string' ? rows.get(payload.value) : undefined;
|
|
49
|
+
const y = Number(rawY);
|
|
50
|
+
if (!row || Number.isNaN(y))
|
|
51
|
+
return null;
|
|
52
|
+
const indent = Math.min(row.bar.depth, 4) * INDENT_PX;
|
|
53
|
+
const room = Math.floor((NAME_PX - indent - 10) / 6.2);
|
|
54
|
+
const name = row.name.length > room ? `${row.name.slice(0, Math.max(1, room - 1))}…` : row.name;
|
|
55
|
+
return (_jsxs("text", { x: indent, y: y, dy: "0.35em", fontSize: 11, fill: row.bar.node.span.status.code === 'ERROR' ? TRACE_HUE.oxblood : 'var(--color-text-secondary)', children: [_jsx("title", { children: row.name }), name] }));
|
|
56
|
+
}
|
|
57
|
+
/** How busy the model and tools were over the turn; a drag across it picks the window to zoom into. */
|
|
58
|
+
function ActivityStrip({ root, zoom, onZoom }) {
|
|
59
|
+
const activity = useMemo(() => traceActivity(root, BUCKETS), [root]);
|
|
60
|
+
const total = Math.max(root.durationMs, 1);
|
|
61
|
+
const [drag, setDrag] = useState(null);
|
|
62
|
+
// Pointer events can outrun a render; the ref always holds the drag so far.
|
|
63
|
+
const dragRef = useRef(null);
|
|
64
|
+
const moveDrag = (next) => {
|
|
65
|
+
dragRef.current = next;
|
|
66
|
+
setDrag(next);
|
|
67
|
+
};
|
|
68
|
+
/** The time under a pointer on the strip, in ms from the turn's start. */
|
|
69
|
+
const timeAt = (event) => {
|
|
70
|
+
const box = event.currentTarget.getBoundingClientRect();
|
|
71
|
+
const share = (event.clientX - box.left - NAME_PX) / Math.max(box.width - NAME_PX - PLOT_RIGHT_PX, 1);
|
|
72
|
+
return Math.min(Math.max(share, 0), 1) * total;
|
|
73
|
+
};
|
|
74
|
+
const endDrag = () => {
|
|
75
|
+
const done = dragRef.current;
|
|
76
|
+
if (done) {
|
|
77
|
+
const from = Math.min(done.from, done.to);
|
|
78
|
+
const to = Math.max(done.from, done.to);
|
|
79
|
+
// A click, not a drag: leave the zoom as it was.
|
|
80
|
+
if (to - from >= total / BUCKETS)
|
|
81
|
+
onZoom({ root: root.id, from, to });
|
|
82
|
+
}
|
|
83
|
+
moveDrag(null);
|
|
84
|
+
};
|
|
85
|
+
const shown = drag ?? zoom;
|
|
86
|
+
return (_jsx("div", { style: { cursor: 'col-resize', userSelect: 'none', touchAction: 'none' }, onPointerDown: (event) => {
|
|
87
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
88
|
+
const value = timeAt(event);
|
|
89
|
+
moveDrag({ from: value, to: value });
|
|
90
|
+
}, onPointerMove: (event) => {
|
|
91
|
+
const current = dragRef.current;
|
|
92
|
+
if (current)
|
|
93
|
+
moveDrag({ from: current.from, to: timeAt(event) });
|
|
94
|
+
}, onPointerUp: endDrag, onPointerCancel: () => moveDrag(null), onMouseDown: (event) => event.preventDefault(), children: _jsx(ResponsiveContainer, { width: "100%", height: STRIP_PX, initialDimension: { width: FIRST_WIDTH_PX, height: STRIP_PX }, children: _jsxs(AreaChart, { data: activity, margin: { top: 2, right: PLOT_RIGHT_PX, bottom: 0, left: NAME_PX }, accessibilityLayer: false, children: [_jsx(XAxis, { dataKey: "at", type: "number", domain: [0, total], hide: true }), _jsx(YAxis, { hide: true, domain: [0, 2] }), _jsx(Area, { type: "monotone", dataKey: "model", stackId: "busy", activeDot: false, stroke: "none", fill: traceFill('clear'), fillOpacity: 1, isAnimationActive: false }), _jsx(Area, { type: "monotone", dataKey: "tools", stackId: "busy", activeDot: false, stroke: "none", fill: traceFill('hatch'), fillOpacity: 1, isAnimationActive: false }), shown ? (_jsx(ReferenceArea, { x1: shown.from, x2: shown.to, fill: "var(--color-text-primary)", fillOpacity: drag ? 0.12 : 0.08, stroke: "var(--color-border-emphasized)" })) : null] }) }) }));
|
|
95
|
+
}
|
|
96
|
+
/** A bar's opacity: faded when the search passed it over, the turn itself half-strength, and the rest dimmed around a selection. */
|
|
97
|
+
function barOpacity(row, selectedId, matches) {
|
|
98
|
+
if (matches && !matches.has(row.id))
|
|
99
|
+
return 0.25;
|
|
100
|
+
if (row.bar.depth === 0)
|
|
101
|
+
return 0.45;
|
|
102
|
+
return !selectedId || row.id === selectedId ? 1 : 0.5;
|
|
103
|
+
}
|
|
104
|
+
/** One bar per span over the time window, named on the left. */
|
|
105
|
+
function SpanBars({ root, domain, selectedId, matches, onSelect, }) {
|
|
106
|
+
const format = useTraceFormat();
|
|
107
|
+
const rows = useMemo(() => traceBars(root).map((bar) => ({
|
|
108
|
+
id: bar.node.id,
|
|
109
|
+
bar,
|
|
110
|
+
range: [bar.from, bar.to],
|
|
111
|
+
name: bar.node.meta.subject ?? bar.node.meta.label,
|
|
112
|
+
})), [root]);
|
|
113
|
+
const byId = useMemo(() => new Map(rows.map((row) => [row.id, row])), [rows]);
|
|
114
|
+
const height = rows.length * ROW_PX + AXIS_PX;
|
|
115
|
+
return (_jsx(ChartFrame, { children: _jsx(ResponsiveContainer, { width: "100%", height: height, initialDimension: { width: FIRST_WIDTH_PX, height }, children: _jsxs(BarChart, { data: rows, layout: "vertical", accessibilityLayer: false, margin: { top: 0, right: PLOT_RIGHT_PX, bottom: 0, left: 0 }, barCategoryGap: 4, onClick: (state) => {
|
|
116
|
+
const row = rows[Number(state?.activeIndex)];
|
|
117
|
+
if (row)
|
|
118
|
+
onSelect(row.bar.node);
|
|
119
|
+
}, style: { cursor: 'pointer' }, children: [_jsx(CartesianGrid, { horizontal: false, stroke: "var(--color-border)", strokeDasharray: "2 4" }), _jsx(XAxis, { type: "number", domain: domain, allowDataOverflow: true, tickFormatter: (value) => format.duration(value), tick: { fill: 'var(--color-text-secondary)', fontSize: 11 }, axisLine: { stroke: 'var(--color-border)' }, tickLine: false, height: AXIS_PX, tickCount: 5 }), _jsx(YAxis, { type: "category", dataKey: "id", width: NAME_PX, axisLine: false, tickLine: false, interval: 0, tick: (props) => _jsx(NameTick, { ...props, rows: byId }) }), _jsx(Tooltip, { content: (props) => _jsx(BarTip, { ...props }), cursor: { fill: 'var(--color-overlay-hover)' }, isAnimationActive: false }), _jsx(Bar, { dataKey: "range", minPointSize: 2, radius: TRACE_RADIUS, isAnimationActive: false, style: { cursor: 'pointer' }, children: rows.map((row) => (_jsx(Cell, { fill: traceFill(barHatch(row.bar.node)), opacity: barOpacity(row, selectedId, matches) }, row.id))) })] }) }) }));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Every span of the turn on one time axis, nested by depth and coloured by
|
|
123
|
+
* who acted. Above it, how busy the model and tools were over the turn; drag
|
|
124
|
+
* across that strip to zoom the rows into the window, as in a performance
|
|
125
|
+
* profile. A bar opens its span.
|
|
126
|
+
*/
|
|
127
|
+
export function TraceWaterfall({ root, selectedId, matches, onSelect, }) {
|
|
128
|
+
const { t } = useTraceFormat();
|
|
129
|
+
const [picked, setPicked] = useState(null);
|
|
130
|
+
const zoom = picked?.root === root.id ? picked : null;
|
|
131
|
+
return (_jsxs(VStack, { gap: 2, children: [_jsxs(HStack, { gap: 2, align: "center", justify: "between", children: [_jsx(Text, { type: "supporting", color: "secondary", children: t('@theorem.panel.trace.timeline.zoom') }), zoom ? (_jsx(Button, { label: t('@theorem.panel.trace.timeline.reset'), variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconZoomOut }), onClick: () => setPicked(null) })) : null] }), _jsx(ActivityStrip, { root: root, zoom: zoom, onZoom: setPicked }), _jsx(SpanBars, { root: root, domain: zoom ? [zoom.from, zoom.to] : [0, Math.max(root.durationMs, 1)], selectedId: selectedId, matches: matches, onSelect: onSelect })] }));
|
|
132
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type VoiceNoteProps = {
|
|
2
|
+
src: string;
|
|
3
|
+
mimeType?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
/** Composer only: removes the staged note. */
|
|
6
|
+
onRemove?: () => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Voice note as an Astryx ClickableCard holding the ink waveform (the one live
|
|
10
|
+
* uses): click to play or pause; the bars move while it plays.
|
|
11
|
+
*/
|
|
12
|
+
export declare function VoiceNote({ src, mimeType, label, onRemove }: VoiceNoteProps): import("react").JSX.Element;
|
package/ui/VoiceNote.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ClickableCard } from '@astryxdesign/core/ClickableCard';
|
|
3
|
+
import { HStack } from '@astryxdesign/core/HStack';
|
|
4
|
+
import { Icon } from '@astryxdesign/core/Icon';
|
|
5
|
+
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
6
|
+
import { VStack } from '@astryxdesign/core/VStack';
|
|
7
|
+
import { IconX } from '@tabler/icons-react';
|
|
8
|
+
import { voiceFormatFromMime } from "../client/voice-label.js";
|
|
9
|
+
import { voiceNoteName } from "./labels.js";
|
|
10
|
+
import { useLabels } from "./labels-provider.js";
|
|
11
|
+
import { InkWaveform } from "../components/InkWaveform.js";
|
|
12
|
+
import { useVoicePlayback } from "../components/use-voice-playback.js";
|
|
13
|
+
/** Astryx Thumbnail's height, so voice notes sit level with image attachments. */
|
|
14
|
+
const VOICE_NOTE_HEIGHT = 64;
|
|
15
|
+
const VOICE_NOTE_WIDTH = 160;
|
|
16
|
+
/**
|
|
17
|
+
* Voice note as an Astryx ClickableCard holding the ink waveform (the one live
|
|
18
|
+
* uses): click to play or pause; the bars move while it plays.
|
|
19
|
+
*/
|
|
20
|
+
export function VoiceNote({ src, mimeType = 'audio/webm', label, onRemove }) {
|
|
21
|
+
const t = useLabels();
|
|
22
|
+
const { playing, outputLevel, toggle, audioProps } = useVoicePlayback();
|
|
23
|
+
const name = label ?? voiceNoteName(t, voiceFormatFromMime(mimeType));
|
|
24
|
+
const remove = t('@theorem.voice_note.remove', { name });
|
|
25
|
+
return (_jsxs(HStack, { gap: 1, vAlign: "center", children: [_jsx(ClickableCard, { label: t(playing ? '@theorem.voice_note.pause' : '@theorem.voice_note.play', { name }), onClick: () => {
|
|
26
|
+
void toggle();
|
|
27
|
+
}, padding: 0, width: VOICE_NOTE_WIDTH, height: VOICE_NOTE_HEIGHT, children: _jsx(VStack, { width: "100%", height: "100%", paddingInline: 2, paddingBlockStart: 2, style: { color: 'var(--color-icon-primary)' }, "aria-hidden": "true", children: _jsx(InkWaveform, { frozen: !playing, outputLevel: outputLevel, status: playing ? 'speaking' : 'ready', variant: "pill" }) }) }), onRemove ? (_jsx(IconButton, { label: remove, tooltip: remove, variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconX }), onClick: onRemove })) : null, _jsx("audio", { ...audioProps, src: src, hidden: true })] }));
|
|
28
|
+
}
|