@twentyfirstmedia/ui-core 0.2.0 → 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/dist/components/admin.d.ts.map +1 -1
- package/dist/components/admin.js +95 -71
- package/dist/components/admin.js.map +1 -1
- package/dist/components/agents.d.ts.map +1 -1
- package/dist/components/agents.js +49 -35
- package/dist/components/agents.js.map +1 -1
- package/dist/components/app-chrome.d.ts.map +1 -1
- package/dist/components/app-chrome.js +6 -2
- package/dist/components/app-chrome.js.map +1 -1
- package/dist/components/approvals.d.ts.map +1 -1
- package/dist/components/approvals.js +22 -18
- package/dist/components/approvals.js.map +1 -1
- package/dist/components/building-blocks.d.ts.map +1 -1
- package/dist/components/building-blocks.js +6 -2
- package/dist/components/building-blocks.js.map +1 -1
- package/dist/components/charts.d.ts.map +1 -1
- package/dist/components/charts.js +20 -10
- package/dist/components/charts.js.map +1 -1
- package/dist/components/chat.d.ts.map +1 -1
- package/dist/components/chat.js +31 -19
- package/dist/components/chat.js.map +1 -1
- package/dist/components/commerce.d.ts +2 -2
- package/dist/components/commerce.d.ts.map +1 -1
- package/dist/components/commerce.js +45 -31
- package/dist/components/commerce.js.map +1 -1
- package/dist/components/data-display.d.ts +5 -9
- package/dist/components/data-display.d.ts.map +1 -1
- package/dist/components/data-display.js +34 -35
- package/dist/components/data-display.js.map +1 -1
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +15 -10
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/developer.d.ts.map +1 -1
- package/dist/components/developer.js +20 -11
- package/dist/components/developer.js.map +1 -1
- package/dist/components/feedback.d.ts.map +1 -1
- package/dist/components/feedback.js +12 -6
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/form.d.ts +2 -1
- package/dist/components/form.d.ts.map +1 -1
- package/dist/components/form.js +12 -9
- package/dist/components/form.js.map +1 -1
- package/dist/components/forms.d.ts +2 -1
- package/dist/components/forms.d.ts.map +1 -1
- package/dist/components/forms.js +92 -42
- package/dist/components/forms.js.map +1 -1
- package/dist/components/foundation.d.ts +5 -2
- package/dist/components/foundation.d.ts.map +1 -1
- package/dist/components/foundation.js +15 -12
- package/dist/components/foundation.js.map +1 -1
- package/dist/components/inputs.d.ts.map +1 -1
- package/dist/components/inputs.js +3 -1
- package/dist/components/inputs.js.map +1 -1
- package/dist/components/mail.d.ts.map +1 -1
- package/dist/components/mail.js +15 -10
- package/dist/components/mail.js.map +1 -1
- package/dist/components/media.d.ts.map +1 -1
- package/dist/components/media.js +39 -18
- package/dist/components/media.js.map +1 -1
- package/dist/components/navigation.d.ts.map +1 -1
- package/dist/components/navigation.js +21 -9
- package/dist/components/navigation.js.map +1 -1
- package/dist/components/operations.d.ts.map +1 -1
- package/dist/components/operations.js +37 -27
- package/dist/components/operations.js.map +1 -1
- package/dist/components/previews.d.ts.map +1 -1
- package/dist/components/previews.js +14 -10
- package/dist/components/previews.js.map +1 -1
- package/dist/components/primitives.d.ts.map +1 -1
- package/dist/components/primitives.js +4 -1
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/real-estate.d.ts.map +1 -1
- package/dist/components/real-estate.js +43 -28
- package/dist/components/real-estate.js.map +1 -1
- package/dist/components/rich-text-editor.d.ts.map +1 -1
- package/dist/components/rich-text-editor.js +18 -15
- package/dist/components/rich-text-editor.js.map +1 -1
- package/dist/components/select-menu.d.ts.map +1 -1
- package/dist/components/select-menu.js +4 -1
- package/dist/components/select-menu.js.map +1 -1
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +8 -3
- package/dist/components/shell.js.map +1 -1
- package/dist/components/site.d.ts.map +1 -1
- package/dist/components/site.js +17 -13
- package/dist/components/site.js.map +1 -1
- package/dist/components/types.d.ts +102 -3
- package/dist/components/types.d.ts.map +1 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +50 -34
- package/dist/components/workspace.js.map +1 -1
- package/dist/context.d.ts +39 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +76 -0
- package/dist/context.js.map +1 -0
- package/dist/format.d.ts +33 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +75 -10
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +18 -11
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +11 -18
- package/dist/provider.js.map +1 -1
- package/dist/strings.d.ts +503 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +537 -0
- package/dist/strings.js.map +1 -0
- package/package.json +1 -1
- package/src/components/admin.tsx +117 -93
- package/src/components/agents.tsx +55 -41
- package/src/components/app-chrome.tsx +6 -2
- package/src/components/approvals.tsx +26 -22
- package/src/components/building-blocks.tsx +6 -2
- package/src/components/charts.tsx +21 -11
- package/src/components/chat.tsx +45 -35
- package/src/components/commerce.tsx +61 -53
- package/src/components/data-display.tsx +38 -45
- package/src/components/data-table.tsx +20 -15
- package/src/components/developer.tsx +26 -15
- package/src/components/feedback.tsx +19 -7
- package/src/components/form.tsx +17 -9
- package/src/components/forms.tsx +131 -53
- package/src/components/foundation.tsx +23 -36
- package/src/components/inputs.tsx +4 -2
- package/src/components/mail.tsx +16 -11
- package/src/components/media.tsx +64 -21
- package/src/components/navigation.tsx +25 -13
- package/src/components/operations.tsx +40 -32
- package/src/components/previews.tsx +17 -15
- package/src/components/primitives.tsx +8 -5
- package/src/components/real-estate.tsx +55 -35
- package/src/components/rich-text-editor.tsx +20 -17
- package/src/components/select-menu.tsx +5 -2
- package/src/components/shell.tsx +8 -3
- package/src/components/site.tsx +18 -14
- package/src/components/types.ts +111 -3
- package/src/components/workspace.tsx +79 -60
- package/src/context.ts +112 -0
- package/src/format.ts +108 -15
- package/src/index.ts +43 -0
- package/src/provider.tsx +36 -40
- package/src/strings.ts +1500 -0
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { useMounted, useWidth } from "../hooks.js";
|
|
5
|
-
import {
|
|
5
|
+
import { useFormat, useStrings } from "../context.js";
|
|
6
|
+
import { CHARTS_STRINGS } from "../strings.js";
|
|
6
7
|
import { cx } from "../cx.js";
|
|
7
8
|
import { Icon } from "../Icon.js";
|
|
8
9
|
import { CountUp } from "./data-display.js";
|
|
@@ -24,6 +25,7 @@ function niceMax(m: number) {
|
|
|
24
25
|
return Math.ceil(m / p) * p;
|
|
25
26
|
}
|
|
26
27
|
export function BarChart(p: BarChartProps) {
|
|
28
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
27
29
|
const mw = useWidth(p.width, 560),
|
|
28
30
|
data = p.data || [],
|
|
29
31
|
W = mw[1],
|
|
@@ -43,7 +45,7 @@ export function BarChart(p: BarChartProps) {
|
|
|
43
45
|
viewBox={"0 0 " + W + " " + (Hh + 22)}
|
|
44
46
|
preserveAspectRatio="xMinYMin meet"
|
|
45
47
|
role="img"
|
|
46
|
-
aria-label={p.label ||
|
|
48
|
+
aria-label={p.label || t.barChart}
|
|
47
49
|
>
|
|
48
50
|
{ticks.map((t) => {
|
|
49
51
|
const y = Hh - t * (Hh - 10);
|
|
@@ -92,6 +94,7 @@ export function BarChart(p: BarChartProps) {
|
|
|
92
94
|
);
|
|
93
95
|
}
|
|
94
96
|
export function LineChart(p: LineChartProps) {
|
|
97
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
95
98
|
const mw = useWidth(p.width, 560),
|
|
96
99
|
series = p.series || [],
|
|
97
100
|
labels = p.labels || [],
|
|
@@ -122,7 +125,7 @@ export function LineChart(p: LineChartProps) {
|
|
|
122
125
|
viewBox={"0 0 " + W + " " + (Hh + 22)}
|
|
123
126
|
preserveAspectRatio="xMinYMin meet"
|
|
124
127
|
role="img"
|
|
125
|
-
aria-label={p.label ||
|
|
128
|
+
aria-label={p.label || t.lineChart}
|
|
126
129
|
>
|
|
127
130
|
{[0, 0.5, 1].map((t) => {
|
|
128
131
|
const y = Hh - t * (Hh - 12);
|
|
@@ -181,6 +184,7 @@ export function LineChart(p: LineChartProps) {
|
|
|
181
184
|
);
|
|
182
185
|
}
|
|
183
186
|
export function Sparkline(p: SparklineProps) {
|
|
187
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
184
188
|
const v = p.values || [],
|
|
185
189
|
W = p.width || 120,
|
|
186
190
|
Hh = p.height || 36,
|
|
@@ -203,7 +207,7 @@ export function Sparkline(p: SparklineProps) {
|
|
|
203
207
|
width={W}
|
|
204
208
|
height={Hh}
|
|
205
209
|
role="img"
|
|
206
|
-
aria-label={p.label ||
|
|
210
|
+
aria-label={p.label || t.trend}
|
|
207
211
|
>
|
|
208
212
|
<path
|
|
209
213
|
className={cx("tf-line", "tf-line-" + (p.tint || "ink"))}
|
|
@@ -217,6 +221,7 @@ export function Sparkline(p: SparklineProps) {
|
|
|
217
221
|
);
|
|
218
222
|
}
|
|
219
223
|
export function Donut(p: DonutProps) {
|
|
224
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
220
225
|
const data = p.data || [],
|
|
221
226
|
size = p.size || 168,
|
|
222
227
|
sw = p.stroke || 22,
|
|
@@ -245,7 +250,7 @@ export function Donut(p: DonutProps) {
|
|
|
245
250
|
height={size}
|
|
246
251
|
viewBox={"0 0 " + size + " " + size}
|
|
247
252
|
role="img"
|
|
248
|
-
aria-label={p.label ||
|
|
253
|
+
aria-label={p.label || t.breakdown}
|
|
249
254
|
>
|
|
250
255
|
<circle className="tf-arc-track" cx={size / 2} cy={size / 2} r={r} strokeWidth={sw} />
|
|
251
256
|
{data.map((d, i) => {
|
|
@@ -361,6 +366,7 @@ export function Legend(p: LegendProps) {
|
|
|
361
366
|
);
|
|
362
367
|
}
|
|
363
368
|
export function StackedBarChart(p: StackedBarChartProps) {
|
|
369
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
364
370
|
const mw = useWidth(p.width, 560),
|
|
365
371
|
W = mw[1],
|
|
366
372
|
Hh = p.height || 200,
|
|
@@ -382,7 +388,7 @@ export function StackedBarChart(p: StackedBarChartProps) {
|
|
|
382
388
|
height={Hh + 22}
|
|
383
389
|
viewBox={"0 0 " + W + " " + (Hh + 22)}
|
|
384
390
|
role="img"
|
|
385
|
-
aria-label={p.label ||
|
|
391
|
+
aria-label={p.label || t.stackedBarChart}
|
|
386
392
|
onPointerLeave={() => {
|
|
387
393
|
hov[1](null);
|
|
388
394
|
}}
|
|
@@ -533,6 +539,7 @@ function smooth(pts: number[][]) {
|
|
|
533
539
|
return d;
|
|
534
540
|
}
|
|
535
541
|
export function AreaChart(p: AreaChartProps) {
|
|
542
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
536
543
|
const mw = useWidth(p.width, 560),
|
|
537
544
|
W = mw[1],
|
|
538
545
|
Hh = p.height || 200,
|
|
@@ -573,7 +580,7 @@ export function AreaChart(p: AreaChartProps) {
|
|
|
573
580
|
height={Hh + 22}
|
|
574
581
|
viewBox={"0 0 " + W + " " + (Hh + 22)}
|
|
575
582
|
role="img"
|
|
576
|
-
aria-label={p.label ||
|
|
583
|
+
aria-label={p.label || t.areaChart}
|
|
577
584
|
onPointerMove={(e) => {
|
|
578
585
|
const r = e.currentTarget.getBoundingClientRect(),
|
|
579
586
|
x = ((e.clientX - r.left) * W) / r.width;
|
|
@@ -672,6 +679,7 @@ export function AreaChart(p: AreaChartProps) {
|
|
|
672
679
|
);
|
|
673
680
|
}
|
|
674
681
|
export function Heatmap(p: HeatmapProps) {
|
|
682
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
675
683
|
const rows = p.rows || [],
|
|
676
684
|
cols = p.cols || [],
|
|
677
685
|
vals = p.values || [],
|
|
@@ -690,7 +698,7 @@ export function Heatmap(p: HeatmapProps) {
|
|
|
690
698
|
gridTemplateColumns: "auto repeat(" + cols.length + ", minmax(0, 1fr))",
|
|
691
699
|
}}
|
|
692
700
|
role="img"
|
|
693
|
-
aria-label={p.label ||
|
|
701
|
+
aria-label={p.label || t.heatmap}
|
|
694
702
|
onPointerLeave={() => {
|
|
695
703
|
hov[1](null);
|
|
696
704
|
}}
|
|
@@ -738,17 +746,18 @@ export function Heatmap(p: HeatmapProps) {
|
|
|
738
746
|
: p.caption || ""}
|
|
739
747
|
</span>
|
|
740
748
|
<span className="tf-heat-scale">
|
|
741
|
-
{
|
|
749
|
+
{t.less}
|
|
742
750
|
{[0, 1, 2, 3, 4].map((l) => (
|
|
743
751
|
<i key={l} className={"tf-heat-cell l" + l} />
|
|
744
752
|
))}
|
|
745
|
-
{
|
|
753
|
+
{t.more}
|
|
746
754
|
</span>
|
|
747
755
|
</div>
|
|
748
756
|
</div>
|
|
749
757
|
);
|
|
750
758
|
}
|
|
751
759
|
export function Funnel(p: FunnelProps) {
|
|
760
|
+
const { formatNumber } = useFormat();
|
|
752
761
|
const steps = p.steps || [],
|
|
753
762
|
top = (steps[0] && steps[0].value) || 1,
|
|
754
763
|
f = p.format || ((v) => formatNumber(v)),
|
|
@@ -791,6 +800,7 @@ export function Funnel(p: FunnelProps) {
|
|
|
791
800
|
);
|
|
792
801
|
}
|
|
793
802
|
export function Gauge(p: GaugeProps) {
|
|
803
|
+
const t = useStrings(CHARTS_STRINGS);
|
|
794
804
|
const size = p.size || 200,
|
|
795
805
|
sw = p.stroke || 18,
|
|
796
806
|
r = (size - sw) / 2,
|
|
@@ -819,7 +829,7 @@ export function Gauge(p: GaugeProps) {
|
|
|
819
829
|
height={size / 2 + sw / 2}
|
|
820
830
|
viewBox={"0 0 " + size + " " + (size / 2 + sw / 2)}
|
|
821
831
|
role="img"
|
|
822
|
-
aria-label={
|
|
832
|
+
aria-label={t.gaugeValue(p.label || t.gauge, v, max)}
|
|
823
833
|
>
|
|
824
834
|
<path
|
|
825
835
|
className="tf-arc-track"
|
package/src/components/chat.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
|
+
import { useFormat, useStrings } from "../context.js";
|
|
4
|
+
import { CHAT_STRINGS } from "../strings.js";
|
|
3
5
|
import { cx } from "../cx.js";
|
|
4
|
-
import { formatNumber } from "../format.js";
|
|
5
6
|
import { Icon } from "../Icon.js";
|
|
6
7
|
import { useControlled } from "../hooks.js";
|
|
7
8
|
import { Avatar, Badge, TintIcon } from "./foundation.js";
|
|
@@ -152,6 +153,7 @@ export function hl(line: string, k: string | number): React.ReactNode[] {
|
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
export function CodeBlock(p: CodeBlockProps) {
|
|
156
|
+
const t = useStrings(CHAT_STRINGS);
|
|
155
157
|
const copied = React.useState(false);
|
|
156
158
|
function copy() {
|
|
157
159
|
try {
|
|
@@ -168,9 +170,9 @@ export function CodeBlock(p: CodeBlockProps) {
|
|
|
168
170
|
<div className="tf-code">
|
|
169
171
|
<div className="tf-code-head">
|
|
170
172
|
<span>{p.lang || "text"}</span>
|
|
171
|
-
<button type="button" className="tf-code-copy" onClick={copy} aria-label=
|
|
173
|
+
<button type="button" className="tf-code-copy" onClick={copy} aria-label={t.copyCode}>
|
|
172
174
|
<Icon name={copied[0] ? "check" : "file"} size={13} />
|
|
173
|
-
{copied[0] ?
|
|
175
|
+
{copied[0] ? t.copied : t.copy}
|
|
174
176
|
</button>
|
|
175
177
|
</div>
|
|
176
178
|
<pre tabIndex={0}>
|
|
@@ -191,8 +193,9 @@ export function CodeBlock(p: CodeBlockProps) {
|
|
|
191
193
|
|
|
192
194
|
/* ── Chat building blocks ── */
|
|
193
195
|
export function TypingDots(p: { label?: string }) {
|
|
196
|
+
const t = useStrings(CHAT_STRINGS);
|
|
194
197
|
return (
|
|
195
|
-
<span className="tf-typing" role="status" aria-label={p.label ||
|
|
198
|
+
<span className="tf-typing" role="status" aria-label={p.label || t.working}>
|
|
196
199
|
<i />
|
|
197
200
|
<i />
|
|
198
201
|
<i />
|
|
@@ -217,6 +220,7 @@ export function AgentMark(p: AgentMarkProps) {
|
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
export function ChatMessage(p: ChatMessageProps) {
|
|
223
|
+
const t = useStrings(CHAT_STRINGS);
|
|
220
224
|
const me = p.role === "user",
|
|
221
225
|
copied = React.useState(false),
|
|
222
226
|
fb = React.useState(p.feedback || null);
|
|
@@ -240,7 +244,7 @@ export function ChatMessage(p: ChatMessageProps) {
|
|
|
240
244
|
return (
|
|
241
245
|
<div className={cx("tf-msg", me ? "me" : "ai", p.className)}>
|
|
242
246
|
{me ? (
|
|
243
|
-
<Avatar name={p.name ||
|
|
247
|
+
<Avatar name={p.name || t.you} size={32} />
|
|
244
248
|
) : (
|
|
245
249
|
<AgentMark tint={p.tint} live={p.streaming} />
|
|
246
250
|
)}
|
|
@@ -301,29 +305,29 @@ export function ChatMessage(p: ChatMessageProps) {
|
|
|
301
305
|
)}
|
|
302
306
|
{!me && !p.streaming && p.actions !== false && (
|
|
303
307
|
<div className="tf-msg-actions">
|
|
304
|
-
<Tooltip label={copied[0] ?
|
|
305
|
-
<button type="button" className="tf-msg-act" aria-label=
|
|
308
|
+
<Tooltip label={copied[0] ? t.copied : t.copy}>
|
|
309
|
+
<button type="button" className="tf-msg-act" aria-label={t.copyReply} onClick={copy}>
|
|
306
310
|
<Icon name={copied[0] ? "check" : "file"} size={14} />
|
|
307
311
|
</button>
|
|
308
312
|
</Tooltip>
|
|
309
313
|
{p.onRetry && (
|
|
310
|
-
<Tooltip label=
|
|
314
|
+
<Tooltip label={t.regenerate}>
|
|
311
315
|
<button
|
|
312
316
|
type="button"
|
|
313
317
|
className="tf-msg-act"
|
|
314
|
-
aria-label=
|
|
318
|
+
aria-label={t.regenerateReply}
|
|
315
319
|
onClick={p.onRetry}
|
|
316
320
|
>
|
|
317
321
|
<Icon name="refresh" size={14} />
|
|
318
322
|
</button>
|
|
319
323
|
</Tooltip>
|
|
320
324
|
)}
|
|
321
|
-
<Tooltip label=
|
|
325
|
+
<Tooltip label={t.goodReply}>
|
|
322
326
|
<button
|
|
323
327
|
type="button"
|
|
324
328
|
className={cx("tf-msg-act", fb[0] === "up" && "on")}
|
|
325
329
|
aria-pressed={fb[0] === "up"}
|
|
326
|
-
aria-label=
|
|
330
|
+
aria-label={t.goodReply}
|
|
327
331
|
onClick={() => {
|
|
328
332
|
fb[1](fb[0] === "up" ? null : "up");
|
|
329
333
|
p.onFeedback && p.onFeedback("up");
|
|
@@ -332,12 +336,12 @@ export function ChatMessage(p: ChatMessageProps) {
|
|
|
332
336
|
<Icon name="thumbUp" size={14} />
|
|
333
337
|
</button>
|
|
334
338
|
</Tooltip>
|
|
335
|
-
<Tooltip label=
|
|
339
|
+
<Tooltip label={t.badReply}>
|
|
336
340
|
<button
|
|
337
341
|
type="button"
|
|
338
342
|
className={cx("tf-msg-act", fb[0] === "down" && "on")}
|
|
339
343
|
aria-pressed={fb[0] === "down"}
|
|
340
|
-
aria-label=
|
|
344
|
+
aria-label={t.badReply}
|
|
341
345
|
onClick={() => {
|
|
342
346
|
fb[1](fb[0] === "down" ? null : "down");
|
|
343
347
|
p.onFeedback && p.onFeedback("down");
|
|
@@ -363,6 +367,7 @@ const TOOL_ICON: Record<string, IconName | null> = {
|
|
|
363
367
|
};
|
|
364
368
|
|
|
365
369
|
export function ToolCall(p: ToolCallProps) {
|
|
370
|
+
const t = useStrings(CHAT_STRINGS);
|
|
366
371
|
const open = React.useState(!!p.defaultOpen),
|
|
367
372
|
st = p.status || "done";
|
|
368
373
|
return (
|
|
@@ -392,13 +397,13 @@ export function ToolCall(p: ToolCallProps) {
|
|
|
392
397
|
<div className="tf-tool-body">
|
|
393
398
|
{p.input != null && (
|
|
394
399
|
<div>
|
|
395
|
-
<span className="tf-tool-label">{
|
|
400
|
+
<span className="tf-tool-label">{t.toolInput}</span>
|
|
396
401
|
<pre>{typeof p.input === "string" ? p.input : JSON.stringify(p.input, null, 2)}</pre>
|
|
397
402
|
</div>
|
|
398
403
|
)}
|
|
399
404
|
{p.output != null && (
|
|
400
405
|
<div>
|
|
401
|
-
<span className="tf-tool-label">{st === "error" ?
|
|
406
|
+
<span className="tf-tool-label">{st === "error" ? t.toolError : t.toolResult}</span>
|
|
402
407
|
<pre className={st === "error" ? "err" : undefined}>
|
|
403
408
|
{typeof p.output === "string" ? p.output : JSON.stringify(p.output, null, 2)}
|
|
404
409
|
</pre>
|
|
@@ -411,6 +416,7 @@ export function ToolCall(p: ToolCallProps) {
|
|
|
411
416
|
}
|
|
412
417
|
|
|
413
418
|
export function Reasoning(p: ReasoningProps) {
|
|
419
|
+
const t = useStrings(CHAT_STRINGS);
|
|
414
420
|
const open = React.useState(!!p.defaultOpen);
|
|
415
421
|
return (
|
|
416
422
|
<div className={cx("tf-reason", open[0] && "open", p.streaming && "live")}>
|
|
@@ -423,7 +429,7 @@ export function Reasoning(p: ReasoningProps) {
|
|
|
423
429
|
}}
|
|
424
430
|
>
|
|
425
431
|
<Icon name="sparkle" size={13} />
|
|
426
|
-
{p.streaming ?
|
|
432
|
+
{p.streaming ? t.thinking : t.thoughtFor(p.duration)}
|
|
427
433
|
<Icon name="chevronDown" size={13} className="tf-tool-chev" />
|
|
428
434
|
</button>
|
|
429
435
|
{open[0] && (
|
|
@@ -470,6 +476,7 @@ export function PromptStarters(p: PromptStartersProps) {
|
|
|
470
476
|
}
|
|
471
477
|
|
|
472
478
|
export function ModelPicker(p: ModelPickerProps) {
|
|
479
|
+
const t = useStrings(CHAT_STRINGS);
|
|
473
480
|
const models = p.models || [],
|
|
474
481
|
cur = models.find((m) => m.id === p.value) || models[0] || {};
|
|
475
482
|
return (
|
|
@@ -493,7 +500,7 @@ export function ModelPicker(p: ModelPickerProps) {
|
|
|
493
500
|
>
|
|
494
501
|
{(s) => (
|
|
495
502
|
<div className="tf-menu tf-menu-static" role="menu">
|
|
496
|
-
<div className="tf-menu-label">{
|
|
503
|
+
<div className="tf-menu-label">{t.model}</div>
|
|
497
504
|
{models.map((m) => (
|
|
498
505
|
<button
|
|
499
506
|
key={m.id}
|
|
@@ -520,6 +527,7 @@ export function ModelPicker(p: ModelPickerProps) {
|
|
|
520
527
|
}
|
|
521
528
|
|
|
522
529
|
export function Composer(p: ComposerProps) {
|
|
530
|
+
const t = useStrings(CHAT_STRINGS);
|
|
523
531
|
const fileRef = React.useRef<HTMLInputElement>(null);
|
|
524
532
|
const ta = React.useRef<HTMLTextAreaElement>(null),
|
|
525
533
|
v = useControlled(p.value, "", p.onChange),
|
|
@@ -559,7 +567,7 @@ export function Composer(p: ComposerProps) {
|
|
|
559
567
|
>
|
|
560
568
|
{cmds.length > 0 && (
|
|
561
569
|
<div className="tf-popover tf-composer-cmds top" role="listbox">
|
|
562
|
-
<div className="tf-menu-label">{
|
|
570
|
+
<div className="tf-menu-label">{t.commands}</div>
|
|
563
571
|
{cmds.map((c, i) => (
|
|
564
572
|
<button
|
|
565
573
|
key={c.name}
|
|
@@ -592,7 +600,7 @@ export function Composer(p: ComposerProps) {
|
|
|
592
600
|
{p.onRemoveAttachment && (
|
|
593
601
|
<button
|
|
594
602
|
type="button"
|
|
595
|
-
aria-label={
|
|
603
|
+
aria-label={t.removeItem(f.name)}
|
|
596
604
|
onClick={() => {
|
|
597
605
|
p.onRemoveAttachment?.(i);
|
|
598
606
|
}}
|
|
@@ -608,8 +616,8 @@ export function Composer(p: ComposerProps) {
|
|
|
608
616
|
ref={ta}
|
|
609
617
|
rows={1}
|
|
610
618
|
className="tf-composer-input"
|
|
611
|
-
placeholder={p.placeholder ||
|
|
612
|
-
aria-label={p.label || p.placeholder ||
|
|
619
|
+
placeholder={p.placeholder || t.messagePlaceholder}
|
|
620
|
+
aria-label={p.label || p.placeholder || t.message}
|
|
613
621
|
value={v[0]}
|
|
614
622
|
disabled={p.disabled}
|
|
615
623
|
onChange={(e) => {
|
|
@@ -642,11 +650,11 @@ export function Composer(p: ComposerProps) {
|
|
|
642
650
|
/>
|
|
643
651
|
<div className="tf-composer-bar">
|
|
644
652
|
{p.onAttach && (
|
|
645
|
-
<Tooltip label=
|
|
653
|
+
<Tooltip label={t.attachFiles}>
|
|
646
654
|
<button
|
|
647
655
|
type="button"
|
|
648
656
|
className="tf-composer-tool"
|
|
649
|
-
aria-label=
|
|
657
|
+
aria-label={t.attachFiles}
|
|
650
658
|
onClick={() => fileRef.current?.click()}
|
|
651
659
|
>
|
|
652
660
|
<Icon name="paperclip" size={16} />
|
|
@@ -665,11 +673,11 @@ export function Composer(p: ComposerProps) {
|
|
|
665
673
|
</Tooltip>
|
|
666
674
|
)}
|
|
667
675
|
{p.commands && (
|
|
668
|
-
<Tooltip label=
|
|
676
|
+
<Tooltip label={t.commands} shortcut="/">
|
|
669
677
|
<button
|
|
670
678
|
type="button"
|
|
671
679
|
className="tf-composer-tool"
|
|
672
|
-
aria-label=
|
|
680
|
+
aria-label={t.commands}
|
|
673
681
|
onClick={() => {
|
|
674
682
|
v[1]("/");
|
|
675
683
|
ta.current && ta.current.focus();
|
|
@@ -681,18 +689,16 @@ export function Composer(p: ComposerProps) {
|
|
|
681
689
|
)}
|
|
682
690
|
{p.models && <ModelPicker models={p.models} value={p.model} onChange={p.onModel} />}
|
|
683
691
|
{p.left}
|
|
684
|
-
<span className="tf-composer-hint">
|
|
685
|
-
{p.hint != null ? p.hint : "Enter to send · Shift+Enter for a new line"}
|
|
686
|
-
</span>
|
|
692
|
+
<span className="tf-composer-hint">{p.hint != null ? p.hint : t.composerHint}</span>
|
|
687
693
|
{p.busy ? (
|
|
688
|
-
<button type="button" className="tf-send stop" aria-label=
|
|
694
|
+
<button type="button" className="tf-send stop" aria-label={t.stop} onClick={p.onStop}>
|
|
689
695
|
<span className="tf-stop-sq" />
|
|
690
696
|
</button>
|
|
691
697
|
) : (
|
|
692
698
|
<button
|
|
693
699
|
type="button"
|
|
694
700
|
className="tf-send"
|
|
695
|
-
aria-label=
|
|
701
|
+
aria-label={t.send}
|
|
696
702
|
disabled={!v[0].trim() && !files.length}
|
|
697
703
|
onClick={send}
|
|
698
704
|
>
|
|
@@ -714,11 +720,12 @@ const AGENT_TONE: Record<string, Tone> = {
|
|
|
714
720
|
};
|
|
715
721
|
|
|
716
722
|
export function AgentStatus(p: AgentStatusProps) {
|
|
723
|
+
const t = useStrings(CHAT_STRINGS);
|
|
717
724
|
const s = p.status || "Idle";
|
|
718
725
|
return (
|
|
719
726
|
<span className="tf-agentstatus">
|
|
720
727
|
<Badge tone={AGENT_TONE[s] || "neutral"} live={s === "Running" || s === "Thinking"}>
|
|
721
|
-
{s}
|
|
728
|
+
{t.agentStatus[s] ?? s}
|
|
722
729
|
</Badge>
|
|
723
730
|
{p.step && <span className="tf-agentstatus-step">{p.step}</span>}
|
|
724
731
|
</span>
|
|
@@ -736,6 +743,8 @@ const TRACE_ICON: Record<string, IconName> = {
|
|
|
736
743
|
};
|
|
737
744
|
|
|
738
745
|
export function RunTrace(p: RunTraceProps) {
|
|
746
|
+
const t = useStrings(CHAT_STRINGS);
|
|
747
|
+
const { formatNumber } = useFormat();
|
|
739
748
|
const steps = p.steps || [],
|
|
740
749
|
total = steps.reduce((a, s) => Math.max(a, (s.start || 0) + (s.ms || 0)), 1),
|
|
741
750
|
sel = React.useState(p.defaultOpen != null ? p.defaultOpen : null);
|
|
@@ -747,8 +756,8 @@ export function RunTrace(p: RunTraceProps) {
|
|
|
747
756
|
return (
|
|
748
757
|
<div className="tf-trace">
|
|
749
758
|
<div className="tf-trace-head">
|
|
750
|
-
<span>{
|
|
751
|
-
<span>{
|
|
759
|
+
<span>{t.step}</span>
|
|
760
|
+
<span>{t.timeline(fms(total))}</span>
|
|
752
761
|
</div>
|
|
753
762
|
{steps.map((s, i) => {
|
|
754
763
|
const open = sel[0] === i,
|
|
@@ -777,7 +786,7 @@ export function RunTrace(p: RunTraceProps) {
|
|
|
777
786
|
width: Math.max(1.5, ((s.ms || 0) / total) * 100) + "%",
|
|
778
787
|
}}
|
|
779
788
|
/>
|
|
780
|
-
<em>{st === "running" ?
|
|
789
|
+
<em>{st === "running" ? t.stepRunning : fms(s.ms || 0)}</em>
|
|
781
790
|
</span>
|
|
782
791
|
</button>
|
|
783
792
|
{open && s.detail && (
|
|
@@ -794,12 +803,13 @@ export function RunTrace(p: RunTraceProps) {
|
|
|
794
803
|
}
|
|
795
804
|
|
|
796
805
|
export function UsageMeter(p: UsageMeterProps) {
|
|
806
|
+
const t = useStrings(CHAT_STRINGS);
|
|
797
807
|
const pct = Math.min(100, ((p.used || 0) / (p.limit || 1)) * 100),
|
|
798
808
|
tone = pct >= 90 ? "blush" : pct >= 70 ? "butter" : "mint";
|
|
799
809
|
return (
|
|
800
810
|
<div className="tf-usage">
|
|
801
811
|
<div className="tf-usage-top">
|
|
802
|
-
<span>{p.label ||
|
|
812
|
+
<span>{p.label || t.context}</span>
|
|
803
813
|
<b>{(p.format || String)(p.used) + " / " + (p.format || String)(p.limit)}</b>
|
|
804
814
|
</div>
|
|
805
815
|
<span className="tf-usage-track">
|