@everfur/sdk 0.1.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/CHANGELOG.md +74 -0
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/animations/package.json +8 -0
- package/chat/package.json +8 -0
- package/client/package.json +8 -0
- package/core/package.json +8 -0
- package/dist/CameraPort-Cv31Pz7g.d.cts +29 -0
- package/dist/CameraPort-Cv31Pz7g.d.ts +29 -0
- package/dist/ChatController-CKdBvPj2.d.ts +146 -0
- package/dist/ChatController-CpUMvvZf.d.cts +146 -0
- package/dist/EverfurResult-D92-uL82.d.cts +240 -0
- package/dist/EverfurResult-D92-uL82.d.ts +240 -0
- package/dist/FilePort-BabWrv7I.d.cts +22 -0
- package/dist/FilePort-BabWrv7I.d.ts +22 -0
- package/dist/PhotoController-BItt5M7u.d.cts +43 -0
- package/dist/PhotoController-D8zMTdcW.d.ts +43 -0
- package/dist/TelemetryPort-BDNr00hu.d.cts +12 -0
- package/dist/TelemetryPort-BDNr00hu.d.ts +12 -0
- package/dist/animations/index.cjs +1997 -0
- package/dist/animations/index.d.cts +517 -0
- package/dist/animations/index.d.ts +517 -0
- package/dist/animations/index.js +1972 -0
- package/dist/cacheEpoch-DknKn3S0.d.cts +36 -0
- package/dist/cacheEpoch-DknKn3S0.d.ts +36 -0
- package/dist/chat/index.cjs +1170 -0
- package/dist/chat/index.d.cts +59 -0
- package/dist/chat/index.d.ts +59 -0
- package/dist/chat/index.js +1167 -0
- package/dist/client/index.cjs +2317 -0
- package/dist/client/index.d.cts +65 -0
- package/dist/client/index.d.ts +65 -0
- package/dist/client/index.js +2217 -0
- package/dist/config-BSjBdxrZ.d.cts +501 -0
- package/dist/config-CiJ0PVBB.d.ts +501 -0
- package/dist/core/index.cjs +3175 -0
- package/dist/core/index.d.cts +70 -0
- package/dist/core/index.d.ts +70 -0
- package/dist/core/index.js +3163 -0
- package/dist/identity-Brl-lDd6.d.cts +91 -0
- package/dist/identity-DK9zORrG.d.ts +91 -0
- package/dist/ids-CJ1S6adf.d.cts +46 -0
- package/dist/ids-CJ1S6adf.d.ts +46 -0
- package/dist/index.cjs +4488 -0
- package/dist/index.d.cts +156 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.js +4464 -0
- package/dist/petsRepository-BEGb97M9.d.cts +326 -0
- package/dist/petsRepository-Bu18r2kK.d.ts +326 -0
- package/dist/photo/index.cjs +2189 -0
- package/dist/photo/index.d.cts +43 -0
- package/dist/photo/index.d.ts +43 -0
- package/dist/photo/index.js +2186 -0
- package/dist/projection-CeIUsbSk.d.cts +8 -0
- package/dist/projection-CeIUsbSk.d.ts +8 -0
- package/dist/records/index.cjs +2840 -0
- package/dist/records/index.d.cts +224 -0
- package/dist/records/index.d.ts +224 -0
- package/dist/records/index.js +2834 -0
- package/dist/requestFunnel-DuUH-kAe.d.cts +28 -0
- package/dist/requestFunnel-dio5OmR9.d.ts +28 -0
- package/dist/resolve-Dq_4_agU.d.cts +86 -0
- package/dist/resolve-Dq_4_agU.d.ts +86 -0
- package/dist/runtime-BgQnA594.d.cts +349 -0
- package/dist/runtime-CBA-LvdM.d.ts +349 -0
- package/dist/server/index.cjs +533 -0
- package/dist/server/index.d.cts +48 -0
- package/dist/server/index.d.ts +48 -0
- package/dist/server/index.js +530 -0
- package/dist/testing/index.cjs +825 -0
- package/dist/testing/index.d.cts +113 -0
- package/dist/testing/index.d.ts +113 -0
- package/dist/testing/index.js +822 -0
- package/dist/testing/rn/index.cjs +449 -0
- package/dist/testing/rn/index.d.cts +49 -0
- package/dist/testing/rn/index.d.ts +49 -0
- package/dist/testing/rn/index.js +444 -0
- package/dist/video/index.cjs +1941 -0
- package/dist/video/index.d.cts +66 -0
- package/dist/video/index.d.ts +66 -0
- package/dist/video/index.js +1938 -0
- package/package.json +311 -0
- package/photo/package.json +8 -0
- package/records/package.json +8 -0
- package/server/device-blocked.cjs +15 -0
- package/server/package.json +9 -0
- package/testing/package.json +8 -0
- package/testing/rn/package.json +8 -0
- package/video/package.json +8 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { createContext, useMemo, useRef, useEffect, useState, useContext } from 'react';
|
|
2
|
+
import 'react-native-safe-area-context';
|
|
3
|
+
import { View, Animated, StyleSheet, Easing, Text } from 'react-native';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/rn/testing.ts
|
|
7
|
+
|
|
8
|
+
// src/client/errors/EverfurResult.ts
|
|
9
|
+
var EverfurConfigError = class _EverfurConfigError extends Error {
|
|
10
|
+
constructor(kind, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "EverfurConfigError";
|
|
13
|
+
this.kind = kind;
|
|
14
|
+
Object.setPrototypeOf(this, _EverfurConfigError.prototype);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/client/theme/tokens.ts
|
|
19
|
+
function deepFreeze(value) {
|
|
20
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
21
|
+
Object.freeze(value);
|
|
22
|
+
for (const key of Object.keys(value)) {
|
|
23
|
+
deepFreeze(value[key]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
var SPACE = { xs: 4, sm: 8, md: 12, lg: 16, xl: 24, xxl: 32 };
|
|
29
|
+
var RADIUS = { tile: 5, xs: 6, sm: 10, md: 14, lg: 20, xl: 28, pill: 500 };
|
|
30
|
+
var TYPE_SIZE = {
|
|
31
|
+
nano: 8,
|
|
32
|
+
small: 9,
|
|
33
|
+
micro: 10,
|
|
34
|
+
tiny: 11,
|
|
35
|
+
caption: 12,
|
|
36
|
+
bodyTight: 13,
|
|
37
|
+
body: 14,
|
|
38
|
+
subtitle: 16,
|
|
39
|
+
heading: 18,
|
|
40
|
+
verdict: 24
|
|
41
|
+
};
|
|
42
|
+
var LINE_HEIGHT = { tight: 1.15, snug: 1.3, normal: 1.4, relaxed: 1.55 };
|
|
43
|
+
var WEIGHT = { regular: "400", medium: "500", bold: "700" };
|
|
44
|
+
var LETTER_SPACING = {
|
|
45
|
+
eyebrow: 1,
|
|
46
|
+
monoWide: 0.9,
|
|
47
|
+
headerBrand: -0.42,
|
|
48
|
+
tight: -0.35
|
|
49
|
+
};
|
|
50
|
+
function baseType() {
|
|
51
|
+
return {
|
|
52
|
+
family: "System",
|
|
53
|
+
mono: "monospace",
|
|
54
|
+
fontUrl: null,
|
|
55
|
+
size: TYPE_SIZE,
|
|
56
|
+
lineHeight: LINE_HEIGHT,
|
|
57
|
+
weight: WEIGHT,
|
|
58
|
+
letterSpacing: LETTER_SPACING
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
var MOTION = {
|
|
62
|
+
duration: { instant: 80, fast: 140, normal: 220, slow: 320 },
|
|
63
|
+
spring: { gentle: { damping: 18, stiffness: 200 } },
|
|
64
|
+
easing: { standard: "cubic-bezier(0.4, 0, 0.2, 1)" },
|
|
65
|
+
reducedMotion: false
|
|
66
|
+
};
|
|
67
|
+
var LIGHT_COLOR = {
|
|
68
|
+
brand: "#10462E",
|
|
69
|
+
brandSoft: "rgba(16,70,46,0.10)",
|
|
70
|
+
brandSofter: "rgba(16,70,46,0.15)",
|
|
71
|
+
brandBorder: "rgba(16,70,46,0.18)",
|
|
72
|
+
borderHairlineGreen: "rgba(16,70,46,0.25)",
|
|
73
|
+
surface: "#FFFFFF",
|
|
74
|
+
surfaceCream: "#FDFBF8",
|
|
75
|
+
surfaceSubtle: "#EFE9E3",
|
|
76
|
+
background: "#FFFFFF",
|
|
77
|
+
borderRingCream: "#D8D2C8",
|
|
78
|
+
text: {
|
|
79
|
+
primary: "#111111",
|
|
80
|
+
secondary: "#0E462E",
|
|
81
|
+
muted: "#6E6660",
|
|
82
|
+
placeholder: "rgba(0,0,0,0.30)",
|
|
83
|
+
onBrand: "#FFFFFF",
|
|
84
|
+
metaCool: "#3D3D3D"
|
|
85
|
+
},
|
|
86
|
+
primary: "#10462E",
|
|
87
|
+
onPrimary: "#FFFFFF",
|
|
88
|
+
accent: "#10462E",
|
|
89
|
+
onAccent: "#FFFFFF",
|
|
90
|
+
accentEdge: "#07C168",
|
|
91
|
+
success: "#07C168",
|
|
92
|
+
danger: "#B91C1C",
|
|
93
|
+
errorRed: "#FF1B00",
|
|
94
|
+
warningStrong: "#A45610",
|
|
95
|
+
cautionAccent: "#D9821D",
|
|
96
|
+
riskConcern: "#EFA700",
|
|
97
|
+
badgeBgPositive: "rgba(7,193,104,0.12)",
|
|
98
|
+
badgeBgCaution: "rgba(217,130,29,0.14)",
|
|
99
|
+
badgeBgCritical: "rgba(185,28,28,0.12)",
|
|
100
|
+
badgeBgNeutral: "rgba(110,102,96,0.12)",
|
|
101
|
+
bubbleUser: "#10462E",
|
|
102
|
+
bubbleAssistant: "#FFFFFF",
|
|
103
|
+
skeleton: "#EFE9E3",
|
|
104
|
+
scanButtonPink: "#FFC3BC",
|
|
105
|
+
checkupCardLowRiskBg: "rgba(7,193,104,0.10)",
|
|
106
|
+
checkupCardConcernBg: "rgba(239,167,0,0.10)"
|
|
107
|
+
};
|
|
108
|
+
var EVERFUR_LIGHT = deepFreeze({
|
|
109
|
+
brightness: "light",
|
|
110
|
+
meta: { displayName: "Everfur", logoUrl: null, placeholder: null, hidePoweredBy: false },
|
|
111
|
+
color: LIGHT_COLOR,
|
|
112
|
+
space: SPACE,
|
|
113
|
+
radius: RADIUS,
|
|
114
|
+
type: baseType(),
|
|
115
|
+
motion: MOTION
|
|
116
|
+
});
|
|
117
|
+
var DARK_COLOR = {
|
|
118
|
+
brand: "#6BD39A",
|
|
119
|
+
brandSoft: "rgba(107,211,154,0.12)",
|
|
120
|
+
brandSofter: "rgba(107,211,154,0.18)",
|
|
121
|
+
brandBorder: "rgba(107,211,154,0.22)",
|
|
122
|
+
borderHairlineGreen: "rgba(107,211,154,0.28)",
|
|
123
|
+
surface: "#1C1F23",
|
|
124
|
+
surfaceCream: "#23272C",
|
|
125
|
+
surfaceSubtle: "#23272C",
|
|
126
|
+
background: "#15171A",
|
|
127
|
+
borderRingCream: "#3A3F45",
|
|
128
|
+
text: {
|
|
129
|
+
primary: "#F5F3F0",
|
|
130
|
+
secondary: "#A9E4C4",
|
|
131
|
+
muted: "#9A938C",
|
|
132
|
+
placeholder: "rgba(255,255,255,0.35)",
|
|
133
|
+
onBrand: "#0E1F17",
|
|
134
|
+
metaCool: "#C9C9C9"
|
|
135
|
+
},
|
|
136
|
+
primary: "#6BD39A",
|
|
137
|
+
onPrimary: "#0E1F17",
|
|
138
|
+
accent: "#6BD39A",
|
|
139
|
+
onAccent: "#0E1F17",
|
|
140
|
+
accentEdge: "#34D888",
|
|
141
|
+
success: "#07C168",
|
|
142
|
+
danger: "#B91C1C",
|
|
143
|
+
errorRed: "#FF1B00",
|
|
144
|
+
warningStrong: "#A45610",
|
|
145
|
+
cautionAccent: "#D9821D",
|
|
146
|
+
riskConcern: "#EFA700",
|
|
147
|
+
badgeBgPositive: "rgba(7,193,104,0.18)",
|
|
148
|
+
badgeBgCaution: "rgba(217,130,29,0.20)",
|
|
149
|
+
badgeBgCritical: "rgba(185,28,28,0.22)",
|
|
150
|
+
badgeBgNeutral: "rgba(255,255,255,0.10)",
|
|
151
|
+
bubbleUser: "#6BD39A",
|
|
152
|
+
bubbleAssistant: "#1C1F23",
|
|
153
|
+
skeleton: "#23272C",
|
|
154
|
+
scanButtonPink: "#FFC3BC",
|
|
155
|
+
checkupCardLowRiskBg: "rgba(7,193,104,0.16)",
|
|
156
|
+
checkupCardConcernBg: "rgba(239,167,0,0.16)"
|
|
157
|
+
};
|
|
158
|
+
deepFreeze({
|
|
159
|
+
brightness: "dark",
|
|
160
|
+
meta: { displayName: "Everfur", logoUrl: null, placeholder: null, hidePoweredBy: false },
|
|
161
|
+
color: DARK_COLOR,
|
|
162
|
+
space: SPACE,
|
|
163
|
+
radius: RADIUS,
|
|
164
|
+
type: baseType(),
|
|
165
|
+
motion: MOTION
|
|
166
|
+
});
|
|
167
|
+
var EVERFUR_THEME_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("@everfur/sdk#EverfurThemeContext@v1");
|
|
168
|
+
var globalThemeHost = globalThis;
|
|
169
|
+
var EverfurThemeContext = globalThemeHost[EVERFUR_THEME_CONTEXT_SYMBOL] ?? (globalThemeHost[EVERFUR_THEME_CONTEXT_SYMBOL] = createContext(EVERFUR_LIGHT));
|
|
170
|
+
EverfurThemeContext.displayName ??= "EverfurThemeContext";
|
|
171
|
+
function useEverfurTheme() {
|
|
172
|
+
return useContext(EverfurThemeContext);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/rn/facade.ts
|
|
176
|
+
var EVERFUR_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("@everfur/sdk#EverfurContext@v1");
|
|
177
|
+
var globalContextHost = globalThis;
|
|
178
|
+
var EverfurContext = globalContextHost[EVERFUR_CONTEXT_SYMBOL] ?? (globalContextHost[EVERFUR_CONTEXT_SYMBOL] = createContext(null));
|
|
179
|
+
EverfurContext.displayName ??= "EverfurContext";
|
|
180
|
+
function useEverfurContext() {
|
|
181
|
+
const ctx = useContext(EverfurContext);
|
|
182
|
+
if (ctx === null) {
|
|
183
|
+
throw new EverfurConfigError(
|
|
184
|
+
"not-initialized",
|
|
185
|
+
"Everfur hooks must be called inside <EverfurProvider>. Wrap your tree once, high."
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return ctx;
|
|
189
|
+
}
|
|
190
|
+
var DOT_SIZE = 6;
|
|
191
|
+
var LOOP_MS = 520;
|
|
192
|
+
var STAGGER_MS = Math.round(LOOP_MS * 0.18);
|
|
193
|
+
var OPACITY_REST = 0.44;
|
|
194
|
+
var OPACITY_STATIC = 0.5;
|
|
195
|
+
var TRI_IN = [0, 0.5, 1];
|
|
196
|
+
var DOT_INDICES = [0, 1, 2];
|
|
197
|
+
function TypingIndicator() {
|
|
198
|
+
const theme = useEverfurTheme();
|
|
199
|
+
const styles = useMemo(() => makeStyles(theme), [theme]);
|
|
200
|
+
const animate = !theme.motion.reducedMotion;
|
|
201
|
+
return /* @__PURE__ */ jsx(
|
|
202
|
+
View,
|
|
203
|
+
{
|
|
204
|
+
style: styles.card,
|
|
205
|
+
accessible: true,
|
|
206
|
+
accessibilityRole: "text",
|
|
207
|
+
accessibilityLabel: "Assistant is typing",
|
|
208
|
+
accessibilityLiveRegion: "polite",
|
|
209
|
+
accessibilityState: { busy: true },
|
|
210
|
+
children: DOT_INDICES.map(
|
|
211
|
+
(index) => animate ? /* @__PURE__ */ jsx(AnimatedDot, { index, style: styles.dot }, index) : /* @__PURE__ */ jsx(View, { style: [styles.dot, styles.dotStatic] }, index)
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
function AnimatedDot({ index, style }) {
|
|
217
|
+
const t = useRef(new Animated.Value(0)).current;
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
const anim = Animated.sequence([
|
|
220
|
+
Animated.delay(index * STAGGER_MS),
|
|
221
|
+
Animated.loop(Animated.timing(t, { toValue: 1, duration: LOOP_MS, useNativeDriver: true }))
|
|
222
|
+
]);
|
|
223
|
+
anim.start();
|
|
224
|
+
return () => anim.stop();
|
|
225
|
+
}, [t, index]);
|
|
226
|
+
const opacity = t.interpolate({ inputRange: TRI_IN, outputRange: [OPACITY_REST, 1, OPACITY_REST] });
|
|
227
|
+
const translateY = t.interpolate({ inputRange: TRI_IN, outputRange: [0, -3.5, 0] });
|
|
228
|
+
return /* @__PURE__ */ jsx(Animated.View, { style: [style, { opacity, transform: [{ translateY }] }] });
|
|
229
|
+
}
|
|
230
|
+
function makeStyles(theme) {
|
|
231
|
+
const c = theme.color;
|
|
232
|
+
const s = theme.space;
|
|
233
|
+
const r = theme.radius;
|
|
234
|
+
return StyleSheet.create({
|
|
235
|
+
card: {
|
|
236
|
+
alignSelf: "flex-start",
|
|
237
|
+
flexDirection: "row",
|
|
238
|
+
alignItems: "center",
|
|
239
|
+
gap: s.xs,
|
|
240
|
+
paddingHorizontal: s.md,
|
|
241
|
+
paddingVertical: s.sm,
|
|
242
|
+
backgroundColor: c.surfaceCream,
|
|
243
|
+
borderRadius: r.md,
|
|
244
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
245
|
+
borderColor: c.brandBorder
|
|
246
|
+
},
|
|
247
|
+
dot: { width: DOT_SIZE, height: DOT_SIZE, borderRadius: r.pill, backgroundColor: c.brand },
|
|
248
|
+
dotStatic: { opacity: OPACITY_STATIC }
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
var ROTATION_PERIOD_MS = 1400;
|
|
252
|
+
var REVEAL_DELAY_MS = 300;
|
|
253
|
+
function AnalyzingIndicator() {
|
|
254
|
+
const theme = useEverfurTheme();
|
|
255
|
+
const styles = useMemo(() => makeStyles2(theme), [theme]);
|
|
256
|
+
const reduced = theme.motion.reducedMotion;
|
|
257
|
+
const [visible, setVisible] = useState(false);
|
|
258
|
+
useEffect(() => {
|
|
259
|
+
const id = setTimeout(() => setVisible(true), REVEAL_DELAY_MS);
|
|
260
|
+
return () => clearTimeout(id);
|
|
261
|
+
}, []);
|
|
262
|
+
const spin = useRef(new Animated.Value(0)).current;
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
if (reduced || !visible) return;
|
|
265
|
+
const loop = Animated.loop(
|
|
266
|
+
Animated.timing(spin, {
|
|
267
|
+
toValue: 1,
|
|
268
|
+
duration: ROTATION_PERIOD_MS,
|
|
269
|
+
easing: Easing.linear,
|
|
270
|
+
useNativeDriver: true
|
|
271
|
+
})
|
|
272
|
+
);
|
|
273
|
+
loop.start();
|
|
274
|
+
return () => loop.stop();
|
|
275
|
+
}, [reduced, visible, spin]);
|
|
276
|
+
const arcMotionStyle = reduced ? null : { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] };
|
|
277
|
+
return /* @__PURE__ */ jsx(
|
|
278
|
+
View,
|
|
279
|
+
{
|
|
280
|
+
style: styles.wrap,
|
|
281
|
+
accessible: true,
|
|
282
|
+
accessibilityState: { busy: true },
|
|
283
|
+
accessibilityLabel: "Analyzing photo",
|
|
284
|
+
children: visible ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
|
+
/* @__PURE__ */ jsx(Animated.View, { style: [styles.ring, arcMotionStyle] }),
|
|
286
|
+
/* @__PURE__ */ jsx(Text, { style: styles.statusLine, children: "Analyzing" })
|
|
287
|
+
] }) : null
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
function makeStyles2(theme) {
|
|
292
|
+
const { color, space, radius, type } = theme;
|
|
293
|
+
const medium = type.weight.medium;
|
|
294
|
+
const ringSize = space.xxl * 2;
|
|
295
|
+
const ringThickness = space.xs;
|
|
296
|
+
return StyleSheet.create({
|
|
297
|
+
wrap: {
|
|
298
|
+
flexGrow: 1,
|
|
299
|
+
alignItems: "center",
|
|
300
|
+
justifyContent: "center",
|
|
301
|
+
padding: space.xl,
|
|
302
|
+
gap: space.md
|
|
303
|
+
},
|
|
304
|
+
// One rotating ring: success on the top/right, cream on the remainder. Only the success sweep is perceptible
|
|
305
|
+
// (the cream half is uniform), so this reads as a cream ring with a rotating success arc - the mobile look.
|
|
306
|
+
ring: {
|
|
307
|
+
width: ringSize,
|
|
308
|
+
height: ringSize,
|
|
309
|
+
borderRadius: radius.pill,
|
|
310
|
+
borderWidth: ringThickness,
|
|
311
|
+
borderTopColor: color.success,
|
|
312
|
+
borderRightColor: color.success,
|
|
313
|
+
borderBottomColor: color.borderRingCream,
|
|
314
|
+
borderLeftColor: color.borderRingCream
|
|
315
|
+
},
|
|
316
|
+
// Neutral SDK-owned structural status word (not clinical / product copy), on the brand-green secondary ramp
|
|
317
|
+
// so it sits in the same family as the verdict hero. Legible in both themes via the token.
|
|
318
|
+
statusLine: {
|
|
319
|
+
color: color.text.secondary,
|
|
320
|
+
fontFamily: type.family,
|
|
321
|
+
fontSize: type.size.subtitle,
|
|
322
|
+
lineHeight: type.size.subtitle * type.lineHeight.snug,
|
|
323
|
+
fontWeight: medium,
|
|
324
|
+
letterSpacing: type.letterSpacing.tight,
|
|
325
|
+
textAlign: "center"
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
var PULSE_PERIOD_MS = 1100;
|
|
330
|
+
var PULSE_MAX_SCALE = 1.6;
|
|
331
|
+
var PULSE_START_OPACITY = 0.35;
|
|
332
|
+
function toneSpec(theme, tier) {
|
|
333
|
+
const { color } = theme;
|
|
334
|
+
switch (tier) {
|
|
335
|
+
case "low_risk":
|
|
336
|
+
return { accent: color.success, wash: color.badgeBgPositive, label: "Low risk", pulse: false };
|
|
337
|
+
case "concern":
|
|
338
|
+
return { accent: color.cautionAccent, wash: color.badgeBgCaution, label: "Concern", pulse: true };
|
|
339
|
+
case "uncertain":
|
|
340
|
+
return { accent: color.text.muted, wash: color.badgeBgNeutral, label: "Uncertain", pulse: false };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function SeverityBadge({ riskTier }) {
|
|
344
|
+
const theme = useEverfurTheme();
|
|
345
|
+
const styles = useMemo(() => makeStyles3(theme), [theme]);
|
|
346
|
+
const pulse = useRef(new Animated.Value(0)).current;
|
|
347
|
+
const spec = riskTier === null ? null : toneSpec(theme, riskTier);
|
|
348
|
+
const shouldPulse = spec !== null && spec.pulse && !theme.motion.reducedMotion;
|
|
349
|
+
useEffect(() => {
|
|
350
|
+
if (!shouldPulse) return;
|
|
351
|
+
const loop = Animated.loop(
|
|
352
|
+
Animated.timing(pulse, {
|
|
353
|
+
toValue: 1,
|
|
354
|
+
duration: PULSE_PERIOD_MS,
|
|
355
|
+
easing: Easing.out(Easing.quad),
|
|
356
|
+
useNativeDriver: true
|
|
357
|
+
})
|
|
358
|
+
);
|
|
359
|
+
loop.start();
|
|
360
|
+
return () => loop.stop();
|
|
361
|
+
}, [shouldPulse, pulse]);
|
|
362
|
+
if (spec === null) return null;
|
|
363
|
+
return /* @__PURE__ */ jsxs(
|
|
364
|
+
View,
|
|
365
|
+
{
|
|
366
|
+
style: [styles.pill, { backgroundColor: spec.wash }],
|
|
367
|
+
accessible: true,
|
|
368
|
+
accessibilityRole: "text",
|
|
369
|
+
accessibilityLabel: spec.label,
|
|
370
|
+
children: [
|
|
371
|
+
/* @__PURE__ */ jsxs(View, { style: styles.dotWrap, children: [
|
|
372
|
+
shouldPulse ? /* @__PURE__ */ jsx(
|
|
373
|
+
Animated.View,
|
|
374
|
+
{
|
|
375
|
+
pointerEvents: "none",
|
|
376
|
+
style: [
|
|
377
|
+
styles.dotRing,
|
|
378
|
+
{
|
|
379
|
+
backgroundColor: spec.accent,
|
|
380
|
+
opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [PULSE_START_OPACITY, 0] }),
|
|
381
|
+
transform: [{ scale: pulse.interpolate({ inputRange: [0, 1], outputRange: [1, PULSE_MAX_SCALE] }) }]
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
) : null,
|
|
386
|
+
/* @__PURE__ */ jsx(View, { style: [styles.dot, { backgroundColor: spec.accent }] })
|
|
387
|
+
] }),
|
|
388
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.label, { color: spec.accent }], children: spec.label })
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
function makeStyles3(theme) {
|
|
394
|
+
const { space, radius, type } = theme;
|
|
395
|
+
const bold = type.weight.bold;
|
|
396
|
+
const dotSize = space.sm;
|
|
397
|
+
return StyleSheet.create({
|
|
398
|
+
pill: {
|
|
399
|
+
alignSelf: "flex-start",
|
|
400
|
+
flexDirection: "row",
|
|
401
|
+
alignItems: "center",
|
|
402
|
+
gap: space.sm,
|
|
403
|
+
paddingHorizontal: space.md,
|
|
404
|
+
paddingVertical: space.xs,
|
|
405
|
+
borderRadius: radius.pill
|
|
406
|
+
},
|
|
407
|
+
dotWrap: {
|
|
408
|
+
width: dotSize,
|
|
409
|
+
height: dotSize,
|
|
410
|
+
alignItems: "center",
|
|
411
|
+
justifyContent: "center"
|
|
412
|
+
},
|
|
413
|
+
dot: {
|
|
414
|
+
width: dotSize,
|
|
415
|
+
height: dotSize,
|
|
416
|
+
borderRadius: radius.pill
|
|
417
|
+
},
|
|
418
|
+
// The pulsing attention ring behind the dot (concern only). backgroundColor + animated opacity/scale set inline.
|
|
419
|
+
dotRing: {
|
|
420
|
+
position: "absolute",
|
|
421
|
+
width: dotSize,
|
|
422
|
+
height: dotSize,
|
|
423
|
+
borderRadius: radius.pill
|
|
424
|
+
},
|
|
425
|
+
label: {
|
|
426
|
+
fontFamily: type.family,
|
|
427
|
+
fontSize: type.size.caption,
|
|
428
|
+
lineHeight: type.size.caption * type.lineHeight.snug,
|
|
429
|
+
fontWeight: bold,
|
|
430
|
+
letterSpacing: type.letterSpacing.eyebrow
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/rn/testing.ts
|
|
436
|
+
function useEverfurTestEntitlements() {
|
|
437
|
+
const { runtime } = useEverfurContext();
|
|
438
|
+
return useMemo(
|
|
439
|
+
() => ({ apply: (snapshot) => runtime.updateEntitlements(snapshot) }),
|
|
440
|
+
[runtime]
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export { AnalyzingIndicator, SeverityBadge, TypingIndicator, useEverfurTestEntitlements };
|