@opengeni/react-native 1.4.5-canary.37615713321001
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 +190 -0
- package/README.md +74 -0
- package/dist/adapters.d.ts +53 -0
- package/dist/adapters.js +3 -0
- package/dist/adapters.js.map +1 -0
- package/dist/attachments.d.ts +75 -0
- package/dist/chunk-3VSZAQ7G.js +391 -0
- package/dist/chunk-3VSZAQ7G.js.map +1 -0
- package/dist/chunk-5ZVK7WKA.js +88 -0
- package/dist/chunk-5ZVK7WKA.js.map +1 -0
- package/dist/chunk-EEDIMY3L.js +240 -0
- package/dist/chunk-EEDIMY3L.js.map +1 -0
- package/dist/chunk-M23SDI4R.js +83 -0
- package/dist/chunk-M23SDI4R.js.map +1 -0
- package/dist/chunk-PHJBSAR3.js +2006 -0
- package/dist/chunk-PHJBSAR3.js.map +1 -0
- package/dist/environment.d.ts +19 -0
- package/dist/expo.d.ts +25 -0
- package/dist/expo.js +267 -0
- package/dist/expo.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +3345 -0
- package/dist/index.js.map +1 -0
- package/dist/presentation.d.ts +262 -0
- package/dist/read-acknowledgement.d.ts +39 -0
- package/dist/realtime/call-events.d.ts +11 -0
- package/dist/realtime/call-view.d.ts +26 -0
- package/dist/realtime/expo-call.d.ts +11 -0
- package/dist/realtime/native-call.d.ts +104 -0
- package/dist/realtime/native-realtime.d.ts +35 -0
- package/dist/realtime/use-native-session-realtime.d.ts +25 -0
- package/dist/session-view.d.ts +87 -0
- package/dist/timeline/activity.d.ts +34 -0
- package/dist/timeline/composer.d.ts +86 -0
- package/dist/timeline/controls.d.ts +27 -0
- package/dist/timeline/decisions.d.ts +29 -0
- package/dist/timeline/feedback.d.ts +26 -0
- package/dist/timeline/icon-nodes.generated.d.ts +738 -0
- package/dist/timeline/icon.d.ts +11 -0
- package/dist/timeline/index.d.ts +32 -0
- package/dist/timeline/index.js +5419 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/markdown.d.ts +11 -0
- package/dist/timeline/markdown.js +415 -0
- package/dist/timeline/markdown.js.map +1 -0
- package/dist/timeline/message-attachments.d.ts +13 -0
- package/dist/timeline/message-timeline.d.ts +36 -0
- package/dist/timeline/model-picker.d.ts +17 -0
- package/dist/timeline/primitives.d.ts +85 -0
- package/dist/timeline/queue-dock.d.ts +19 -0
- package/dist/timeline/session-actions.d.ts +34 -0
- package/dist/timeline/session-list.d.ts +50 -0
- package/dist/timeline/session-screen.d.ts +35 -0
- package/dist/timeline/session-signals.d.ts +37 -0
- package/dist/timeline/sheet.d.ts +14 -0
- package/dist/timeline/theme.d.ts +58 -0
- package/dist/timeline/thinking-orb.d.ts +13 -0
- package/dist/timeline/turn.d.ts +80 -0
- package/dist/ui/attention.d.ts +14 -0
- package/dist/ui/cards.d.ts +21 -0
- package/dist/ui/composer.d.ts +21 -0
- package/dist/ui/format.d.ts +13 -0
- package/dist/ui/icons.d.ts +9 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +1757 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/steps-sheet.d.ts +10 -0
- package/dist/ui/theme.d.ts +63 -0
- package/dist/ui/timeline.d.ts +48 -0
- package/dist/ui/web-tokens.gen.d.ts +90 -0
- package/dist/use-native-session.d.ts +40 -0
- package/dist/view-model.d.ts +52 -0
- package/dist/voice-input.d.ts +102 -0
- package/dist/webrtc.d.ts +9 -0
- package/dist/webrtc.js +19 -0
- package/dist/webrtc.js.map +1 -0
- package/expo-module.config.json +7 -0
- package/ios/OpenGeniCall.podspec +22 -0
- package/ios/OpenGeniCallAppDelegateSubscriber.swift +29 -0
- package/ios/OpenGeniCallCenter.swift +189 -0
- package/ios/OpenGeniCallModule.swift +64 -0
- package/package.json +93 -0
- package/src/adapters.ts +150 -0
- package/src/attachments.ts +396 -0
- package/src/environment.tsx +214 -0
- package/src/expo.ts +295 -0
- package/src/index.ts +98 -0
- package/src/presentation.ts +285 -0
- package/src/read-acknowledgement.ts +72 -0
- package/src/realtime/call-events.ts +41 -0
- package/src/realtime/call-view.tsx +220 -0
- package/src/realtime/expo-call.ts +49 -0
- package/src/realtime/native-call.ts +266 -0
- package/src/realtime/native-realtime.ts +115 -0
- package/src/realtime/use-native-session-realtime.ts +29 -0
- package/src/session-view.tsx +2251 -0
- package/src/timeline/activity.tsx +736 -0
- package/src/timeline/composer.tsx +686 -0
- package/src/timeline/controls.tsx +151 -0
- package/src/timeline/decisions.tsx +651 -0
- package/src/timeline/feedback.tsx +251 -0
- package/src/timeline/icon-nodes.generated.ts +1830 -0
- package/src/timeline/icon.tsx +44 -0
- package/src/timeline/index.ts +67 -0
- package/src/timeline/markdown.tsx +510 -0
- package/src/timeline/message-attachments.tsx +155 -0
- package/src/timeline/message-timeline.tsx +1042 -0
- package/src/timeline/model-picker.tsx +450 -0
- package/src/timeline/primitives.tsx +561 -0
- package/src/timeline/queue-dock.tsx +331 -0
- package/src/timeline/session-actions.tsx +379 -0
- package/src/timeline/session-list.tsx +338 -0
- package/src/timeline/session-screen.tsx +488 -0
- package/src/timeline/session-signals.tsx +312 -0
- package/src/timeline/sheet.tsx +153 -0
- package/src/timeline/theme.tsx +128 -0
- package/src/timeline/thinking-orb.tsx +93 -0
- package/src/timeline/turn.tsx +569 -0
- package/src/ui/attention.tsx +220 -0
- package/src/ui/cards.tsx +267 -0
- package/src/ui/composer.tsx +296 -0
- package/src/ui/format.ts +86 -0
- package/src/ui/icons.tsx +131 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/steps-sheet.tsx +71 -0
- package/src/ui/theme.ts +261 -0
- package/src/ui/timeline.tsx +837 -0
- package/src/ui/web-tokens.gen.ts +94 -0
- package/src/use-native-session.ts +219 -0
- package/src/view-model.ts +485 -0
- package/src/voice-input.ts +382 -0
- package/src/webrtc.ts +30 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import type { ClientModel, Session, SessionStatus } from "@opengeni/sdk";
|
|
2
|
+
import { SESSION_STATUS_BADGE, SESSION_STATUS_PRESENTATION } from "@opengeni/react/timeline-model";
|
|
3
|
+
import { MODEL_MARK_PATHS, modelMarkVendor } from "@opengeni/react/model-mark-paths";
|
|
4
|
+
import { projectClientModelRows } from "@opengeni/react/model-policy";
|
|
5
|
+
import {
|
|
6
|
+
recentSessionModelPresentation,
|
|
7
|
+
recentSessionStatus,
|
|
8
|
+
relativeTimeLabel,
|
|
9
|
+
sessionDisplayTitle,
|
|
10
|
+
sessionRepoLabel,
|
|
11
|
+
type SessionStatusTone,
|
|
12
|
+
} from "@opengeni/react/session-list-model";
|
|
13
|
+
import { useEffect, useMemo } from "react";
|
|
14
|
+
import { Platform, Pressable, Text, useWindowDimensions, View } from "react-native";
|
|
15
|
+
import Animated, {
|
|
16
|
+
cancelAnimation,
|
|
17
|
+
Easing,
|
|
18
|
+
useAnimatedStyle,
|
|
19
|
+
useReducedMotion,
|
|
20
|
+
useSharedValue,
|
|
21
|
+
withRepeat,
|
|
22
|
+
withTiming,
|
|
23
|
+
} from "react-native-reanimated";
|
|
24
|
+
import Svg, { Path } from "react-native-svg";
|
|
25
|
+
import { Icon } from "./icon";
|
|
26
|
+
import { withAlpha } from "./primitives";
|
|
27
|
+
import { fontStyle, useNativeTimelineTheme, type WebColorToken } from "./theme";
|
|
28
|
+
|
|
29
|
+
/* ----------------------------------------------------------------------------
|
|
30
|
+
The web app's session list rows at phone width (Recent sessions on the
|
|
31
|
+
home canvas): status dot, title, maker mark + catalog model label, and a
|
|
32
|
+
compact relative time. Ordering and labels come from the shared
|
|
33
|
+
session-list model so web and native read identically.
|
|
34
|
+
-------------------------------------------------------------------------- */
|
|
35
|
+
|
|
36
|
+
const TONE_COLOR: Record<SessionStatusTone, WebColorToken> = {
|
|
37
|
+
queued: "status-queued",
|
|
38
|
+
running: "status-running",
|
|
39
|
+
waiting: "status-waiting",
|
|
40
|
+
idle: "status-idle",
|
|
41
|
+
failed: "status-failed",
|
|
42
|
+
cancelled: "status-cancelled",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** The web StatusDot: an 8pt dot with a gentle pulse for live states. */
|
|
46
|
+
export function StatusDot({
|
|
47
|
+
tone,
|
|
48
|
+
pulse,
|
|
49
|
+
size = 8,
|
|
50
|
+
}: {
|
|
51
|
+
tone: SessionStatusTone;
|
|
52
|
+
pulse?: boolean;
|
|
53
|
+
size?: number;
|
|
54
|
+
}) {
|
|
55
|
+
const theme = useNativeTimelineTheme();
|
|
56
|
+
const reduceMotion = useReducedMotion();
|
|
57
|
+
const opacity = useSharedValue(1);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!pulse || reduceMotion) {
|
|
60
|
+
cancelAnimation(opacity);
|
|
61
|
+
opacity.value = 1;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Tailwind animate-pulse: 2s, cubic-bezier(0.4, 0, 0.6, 1), 1 → 0.5 → 1.
|
|
65
|
+
opacity.value = withRepeat(
|
|
66
|
+
withTiming(0.5, { duration: 1000, easing: Easing.bezier(0.4, 0, 0.6, 1) }),
|
|
67
|
+
-1,
|
|
68
|
+
true,
|
|
69
|
+
);
|
|
70
|
+
return () => cancelAnimation(opacity);
|
|
71
|
+
}, [opacity, pulse, reduceMotion]);
|
|
72
|
+
const style = useAnimatedStyle(() => ({ opacity: opacity.value }));
|
|
73
|
+
return (
|
|
74
|
+
<Animated.View
|
|
75
|
+
accessibilityElementsHidden
|
|
76
|
+
importantForAccessibility="no"
|
|
77
|
+
style={[
|
|
78
|
+
{
|
|
79
|
+
width: size,
|
|
80
|
+
height: size,
|
|
81
|
+
borderRadius: size / 2,
|
|
82
|
+
backgroundColor: theme.colors[TONE_COLOR[tone]],
|
|
83
|
+
},
|
|
84
|
+
style,
|
|
85
|
+
]}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The model maker's logo (OpenAI, Claude, Grok) with the web's neutral fallback. */
|
|
91
|
+
export function ModelMark({
|
|
92
|
+
model,
|
|
93
|
+
size = 12,
|
|
94
|
+
color,
|
|
95
|
+
}: {
|
|
96
|
+
model: string;
|
|
97
|
+
size?: number;
|
|
98
|
+
color: string;
|
|
99
|
+
}) {
|
|
100
|
+
const vendor = modelMarkVendor(model);
|
|
101
|
+
if (!vendor) return <Icon name="sparkles" size={size} color={color} />;
|
|
102
|
+
return (
|
|
103
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" accessibilityElementsHidden>
|
|
104
|
+
<Path d={MODEL_MARK_PATHS[vendor]} fill={color} />
|
|
105
|
+
</Svg>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface SessionRowProps {
|
|
110
|
+
session: Session;
|
|
111
|
+
/** The deployment's client model catalog, for catalog labels. */
|
|
112
|
+
models: readonly ClientModel[];
|
|
113
|
+
onPress: () => void;
|
|
114
|
+
now?: Date | undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** One recent-session row, as the web home canvas renders it. */
|
|
118
|
+
export function SessionRow({ session, models, onPress, now }: SessionRowProps) {
|
|
119
|
+
const theme = useNativeTimelineTheme();
|
|
120
|
+
const c = theme.colors;
|
|
121
|
+
const rows = useMemo(() => projectClientModelRows([...models]), [models]);
|
|
122
|
+
const title = sessionDisplayTitle(session);
|
|
123
|
+
const status = recentSessionStatus(session);
|
|
124
|
+
const model = recentSessionModelPresentation(session.model, rows);
|
|
125
|
+
const repo = sessionRepoLabel(session);
|
|
126
|
+
const meta = [model.label, repo].filter(Boolean).join(" · ");
|
|
127
|
+
return (
|
|
128
|
+
<Pressable
|
|
129
|
+
accessibilityRole="button"
|
|
130
|
+
accessibilityLabel={title}
|
|
131
|
+
onPress={onPress}
|
|
132
|
+
style={({ pressed }) => ({
|
|
133
|
+
flexDirection: "row",
|
|
134
|
+
alignItems: "center",
|
|
135
|
+
gap: 12,
|
|
136
|
+
paddingHorizontal: 4,
|
|
137
|
+
paddingVertical: 10,
|
|
138
|
+
borderRadius: theme.radius.md,
|
|
139
|
+
backgroundColor: pressed ? c.hover : "transparent",
|
|
140
|
+
})}
|
|
141
|
+
>
|
|
142
|
+
<StatusDot tone={status.tone} pulse={status.pulse} />
|
|
143
|
+
<View style={{ flex: 1, minWidth: 0 }}>
|
|
144
|
+
<Text
|
|
145
|
+
numberOfLines={1}
|
|
146
|
+
style={{ ...fontStyle(theme, 400), fontSize: 14, lineHeight: 20, color: c.fg }}
|
|
147
|
+
>
|
|
148
|
+
{title}
|
|
149
|
+
</Text>
|
|
150
|
+
{meta ? (
|
|
151
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 6, marginTop: 2 }}>
|
|
152
|
+
<ModelMark model={session.model} size={12} color={c["fg-muted"]} />
|
|
153
|
+
<Text
|
|
154
|
+
numberOfLines={1}
|
|
155
|
+
style={{
|
|
156
|
+
...fontStyle(theme, 400),
|
|
157
|
+
fontSize: 11,
|
|
158
|
+
lineHeight: 16,
|
|
159
|
+
color: c["fg-subtle"],
|
|
160
|
+
flexShrink: 1,
|
|
161
|
+
}}
|
|
162
|
+
>
|
|
163
|
+
{meta}
|
|
164
|
+
</Text>
|
|
165
|
+
</View>
|
|
166
|
+
) : null}
|
|
167
|
+
</View>
|
|
168
|
+
<Text
|
|
169
|
+
style={{
|
|
170
|
+
...fontStyle(theme, 400),
|
|
171
|
+
fontSize: 11,
|
|
172
|
+
lineHeight: 16,
|
|
173
|
+
color: c["fg-subtle"],
|
|
174
|
+
fontVariant: ["tabular-nums"],
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
{relativeTimeLabel(session.updatedAt, now)}
|
|
178
|
+
</Text>
|
|
179
|
+
</Pressable>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** A small-caps section label (web: text-2xs semibold uppercase tracking-wider). */
|
|
184
|
+
export function SectionLabel({ children }: { children: string }) {
|
|
185
|
+
const theme = useNativeTimelineTheme();
|
|
186
|
+
return (
|
|
187
|
+
<Text
|
|
188
|
+
accessibilityRole="header"
|
|
189
|
+
style={{
|
|
190
|
+
...fontStyle(theme, 600),
|
|
191
|
+
fontSize: 11,
|
|
192
|
+
lineHeight: 16,
|
|
193
|
+
letterSpacing: 0.55,
|
|
194
|
+
textTransform: "uppercase",
|
|
195
|
+
color: theme.colors.fg,
|
|
196
|
+
paddingHorizontal: 2,
|
|
197
|
+
marginBottom: 6,
|
|
198
|
+
}}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
</Text>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** The web's divided list: rows separated by a hairline in border/60. */
|
|
206
|
+
export function SessionRowList(props: {
|
|
207
|
+
sessions: readonly Session[];
|
|
208
|
+
models: readonly ClientModel[];
|
|
209
|
+
onOpen: (sessionId: string) => void;
|
|
210
|
+
}) {
|
|
211
|
+
const theme = useNativeTimelineTheme();
|
|
212
|
+
return (
|
|
213
|
+
<View>
|
|
214
|
+
{props.sessions.map((session, index) => (
|
|
215
|
+
<View
|
|
216
|
+
key={session.id}
|
|
217
|
+
style={
|
|
218
|
+
index > 0
|
|
219
|
+
? {
|
|
220
|
+
borderTopWidth: 1,
|
|
221
|
+
borderColor: theme.colors.border,
|
|
222
|
+
borderTopColor: withAlpha(theme.colors.border, 0.6),
|
|
223
|
+
}
|
|
224
|
+
: undefined
|
|
225
|
+
}
|
|
226
|
+
>
|
|
227
|
+
<SessionRow
|
|
228
|
+
session={session}
|
|
229
|
+
models={props.models}
|
|
230
|
+
onPress={() => props.onOpen(session.id)}
|
|
231
|
+
/>
|
|
232
|
+
</View>
|
|
233
|
+
))}
|
|
234
|
+
</View>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** The web session status badge: tinted pill, breathing dot for live states. */
|
|
239
|
+
export function SessionStatusBadge({ status, label }: { status: SessionStatus; label?: string }) {
|
|
240
|
+
const theme = useNativeTimelineTheme();
|
|
241
|
+
const c = theme.colors;
|
|
242
|
+
const presentation = SESSION_STATUS_PRESENTATION[status];
|
|
243
|
+
const badge = SESSION_STATUS_BADGE[status];
|
|
244
|
+
const color = (token: string) => c[token as WebColorToken] ?? c["fg-muted"];
|
|
245
|
+
return (
|
|
246
|
+
<View
|
|
247
|
+
accessibilityRole="text"
|
|
248
|
+
accessibilityLabel={`Status: ${label ?? presentation.label}`}
|
|
249
|
+
style={{
|
|
250
|
+
flexDirection: "row",
|
|
251
|
+
alignItems: "center",
|
|
252
|
+
gap: 6,
|
|
253
|
+
paddingHorizontal: 8,
|
|
254
|
+
paddingVertical: 2,
|
|
255
|
+
borderRadius: 999,
|
|
256
|
+
borderWidth: 1,
|
|
257
|
+
borderColor: withAlpha(color(badge.border), badge.borderAlpha),
|
|
258
|
+
backgroundColor: withAlpha(color(badge.fill), 0.1),
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
<StatusDot tone={presentation.tone} pulse={presentation.pulse} size={6} />
|
|
262
|
+
<Text
|
|
263
|
+
style={{ ...fontStyle(theme, 500), fontSize: 12, lineHeight: 16, color: color(badge.text) }}
|
|
264
|
+
>
|
|
265
|
+
{label ?? presentation.label}
|
|
266
|
+
</Text>
|
|
267
|
+
</View>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* A native navigation-bar title for a session: the title on one line and, under
|
|
273
|
+
* it, the run state as a status dot and quiet label (the web header badge's
|
|
274
|
+
* information without boxing a pill inside the bar's glass).
|
|
275
|
+
*/
|
|
276
|
+
export function SessionHeaderTitle({
|
|
277
|
+
title,
|
|
278
|
+
status,
|
|
279
|
+
statusLabel,
|
|
280
|
+
align = Platform.OS === "ios" ? "center" : "left",
|
|
281
|
+
}: {
|
|
282
|
+
title: string;
|
|
283
|
+
status: SessionStatus | null;
|
|
284
|
+
/** Override the label ("Paused" for a paused workstream). */
|
|
285
|
+
statusLabel?: string | undefined;
|
|
286
|
+
align?: "center" | "left";
|
|
287
|
+
}) {
|
|
288
|
+
const theme = useNativeTimelineTheme();
|
|
289
|
+
const c = theme.colors;
|
|
290
|
+
const viewport = useWindowDimensions();
|
|
291
|
+
const presentation = status ? SESSION_STATUS_PRESENTATION[status] : null;
|
|
292
|
+
// A settled, idle session needs no status line: the title stands alone, as in
|
|
293
|
+
// native messaging apps. Running, waiting, paused and failed states still say so.
|
|
294
|
+
const label = statusLabel ?? (status === "idle" ? undefined : presentation?.label);
|
|
295
|
+
// Live and attention states take their status colour; settled ones stay quiet.
|
|
296
|
+
const emphasized =
|
|
297
|
+
presentation?.tone === "running" ||
|
|
298
|
+
presentation?.tone === "waiting" ||
|
|
299
|
+
presentation?.tone === "failed";
|
|
300
|
+
return (
|
|
301
|
+
<View
|
|
302
|
+
accessible
|
|
303
|
+
accessibilityRole="header"
|
|
304
|
+
accessibilityLabel={label ? `${title}, ${label}` : title}
|
|
305
|
+
// iOS sizes a custom title view once, often before the session (and its
|
|
306
|
+
// title) has loaded; a fixed width keeps a late title from collapsing to
|
|
307
|
+
// "H…". The bar's back and actions buttons take about 150pt.
|
|
308
|
+
style={
|
|
309
|
+
align === "center"
|
|
310
|
+
? { alignItems: "center", width: Math.max(120, Math.min(260, viewport.width - 150)) }
|
|
311
|
+
: { alignItems: "flex-start", maxWidth: 240 }
|
|
312
|
+
}
|
|
313
|
+
>
|
|
314
|
+
<Text
|
|
315
|
+
numberOfLines={1}
|
|
316
|
+
style={{ ...fontStyle(theme, 600), fontSize: 16, lineHeight: 20, color: c.fg }}
|
|
317
|
+
>
|
|
318
|
+
{title}
|
|
319
|
+
</Text>
|
|
320
|
+
{presentation && label ? (
|
|
321
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 5, marginTop: 1 }}>
|
|
322
|
+
<StatusDot tone={presentation.tone} pulse={presentation.pulse} size={6} />
|
|
323
|
+
<Text
|
|
324
|
+
numberOfLines={1}
|
|
325
|
+
style={{
|
|
326
|
+
...fontStyle(theme, 500),
|
|
327
|
+
fontSize: 12,
|
|
328
|
+
lineHeight: 15,
|
|
329
|
+
color: emphasized ? c[TONE_COLOR[presentation.tone]] : c["fg-muted"],
|
|
330
|
+
}}
|
|
331
|
+
>
|
|
332
|
+
{label}
|
|
333
|
+
</Text>
|
|
334
|
+
</View>
|
|
335
|
+
) : null}
|
|
336
|
+
</View>
|
|
337
|
+
);
|
|
338
|
+
}
|