bleam 0.0.12 → 0.0.14
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/ai.cjs +5 -4
- package/dist/ai.js +4 -3
- package/dist/app-storage-D8W4n8ey.cjs +39 -0
- package/dist/app-storage-Isi5Bo0R.js +34 -0
- package/dist/cli.cjs +149 -23
- package/dist/cli.d.cts +13 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +149 -23
- package/dist/elements-DX_YUveu.d.ts +341 -0
- package/dist/elements-gEI8YGl1.d.cts +341 -0
- package/dist/elements.cjs +1031 -0
- package/dist/elements.d.cts +2 -0
- package/dist/elements.d.ts +2 -0
- package/dist/elements.js +999 -0
- package/dist/{files-BXVkPrPN.js → files-DErLhzCB.js} +5 -11
- package/dist/{files-DxaQ-Nv0.cjs → files-lMk-CpL_.cjs} +5 -11
- package/dist/files.cjs +1 -1
- package/dist/files.js +1 -1
- package/dist/schema.cjs +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/dist/secrets.cjs +146 -0
- package/dist/secrets.d.cts +14 -0
- package/dist/secrets.d.ts +14 -0
- package/dist/secrets.js +142 -0
- package/dist/{state-LssDgpff.cjs → state-Bm9GiRnU.cjs} +61 -47
- package/dist/{state-Dh3HLixb.js → state-D8Firo9w.js} +60 -41
- package/dist/state.cjs +3 -2
- package/dist/state.d.cts +1 -1
- package/dist/state.d.ts +1 -1
- package/dist/state.js +3 -2
- package/dist/window.d.cts +1 -1
- package/dist/window.d.ts +1 -1
- package/package.json +14 -11
- package/templates/basic/app/index.tsx +7 -129
- package/templates/foundation-models/app/index.tsx +100 -41
- package/templates/image-generation/app/index.tsx +2 -2
- package/templates/native/ios/Podfile.lock +6 -0
- package/templates/native/modules/bleam-runtime/ios/AIModule.swift +7 -8
- package/templates/native/package.json +6 -1
- package/templates/native/yarn.lock +5392 -3749
- package/templates/state/app/index.tsx +2 -2
- package/templates/text-generation/app/index.tsx +4 -4
- package/templates/updates/README.md +1 -1
- package/dist/native-sqlite-xcGdamRD.js +0 -64
- package/dist/native-sqlite-yQLD5s9i.cjs +0 -66
- package/dist/ui-1WepaMS4.d.cts +0 -92
- package/dist/ui-D7bRLYee.d.ts +0 -92
- package/dist/ui.cjs +0 -364
- package/dist/ui.d.cts +0 -2
- package/dist/ui.d.ts +0 -2
- package/dist/ui.js +0 -357
- /package/dist/{schema-B5BfdswF.js → schema-B7ELMpuI.js} +0 -0
- /package/dist/{schema-BnVZOXfu.cjs → schema-B7SLUBLN.cjs} +0 -0
- /package/dist/{schema-D5eImHxu.d.cts → schema-BWsDPc6c.d.cts} +0 -0
- /package/dist/{schema-SSjokbtw.d.ts → schema-DsXZBnvc.d.ts} +0 -0
package/dist/elements.js
ADDED
|
@@ -0,0 +1,999 @@
|
|
|
1
|
+
import { t as ensureNativeScript } from "./native-runtime-C85Nuc4F.js";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { ActivityIndicator, FlatList, PlatformColor, Pressable, StyleSheet, Text, TextInput, View, processColor } from "react-native";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/elements/ai-status.ts
|
|
7
|
+
function messageStatusDisplay(status) {
|
|
8
|
+
switch (status) {
|
|
9
|
+
case "queued": return {
|
|
10
|
+
symbol: "clock",
|
|
11
|
+
label: "Queued",
|
|
12
|
+
color: "systemGray"
|
|
13
|
+
};
|
|
14
|
+
case "generating": return {
|
|
15
|
+
symbol: "ellipsis",
|
|
16
|
+
label: "Generating",
|
|
17
|
+
color: "systemBlue"
|
|
18
|
+
};
|
|
19
|
+
case "canceling": return {
|
|
20
|
+
symbol: "xmark.circle",
|
|
21
|
+
label: "Canceling",
|
|
22
|
+
color: "systemOrange"
|
|
23
|
+
};
|
|
24
|
+
case "failed": return {
|
|
25
|
+
symbol: "exclamationmark.triangle",
|
|
26
|
+
label: "Failed",
|
|
27
|
+
color: "systemRed"
|
|
28
|
+
};
|
|
29
|
+
case "canceled": return {
|
|
30
|
+
symbol: "xmark.circle",
|
|
31
|
+
label: "Canceled",
|
|
32
|
+
color: "systemOrange"
|
|
33
|
+
};
|
|
34
|
+
default: return {
|
|
35
|
+
symbol: "checkmark",
|
|
36
|
+
label: "Completed",
|
|
37
|
+
color: "systemGray"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function promptStatusGenerating(status) {
|
|
42
|
+
return status === "queued" || status === "generating" || status === "canceling";
|
|
43
|
+
}
|
|
44
|
+
function promptStatusSymbol(status, generating) {
|
|
45
|
+
if (generating) return "stop.fill";
|
|
46
|
+
if (status === "failed" || status === "canceled") return "exclamationmark.arrow.triangle.2.circlepath";
|
|
47
|
+
return "arrow.up";
|
|
48
|
+
}
|
|
49
|
+
function promptStatusLabel(status, generating) {
|
|
50
|
+
if (generating) return "Stop generating";
|
|
51
|
+
if (status === "failed") return "Send after failure";
|
|
52
|
+
if (status === "canceled") return "Send after cancellation";
|
|
53
|
+
return "Send message";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/elements/shared.ts
|
|
58
|
+
function textFromChildren(children) {
|
|
59
|
+
if (typeof children === "string" || typeof children === "number") return String(children);
|
|
60
|
+
if (Array.isArray(children)) return children.filter((child) => typeof child === "string" || typeof child === "number").join("");
|
|
61
|
+
}
|
|
62
|
+
function styleFromProps(style) {
|
|
63
|
+
return StyleSheet.flatten(style);
|
|
64
|
+
}
|
|
65
|
+
function colorFromHex(hex) {
|
|
66
|
+
const value = hex.trim().replace(/^#/, "");
|
|
67
|
+
const normalized = value.length === 3 ? value.split("").map((part) => `${part}${part}`).join("") : value;
|
|
68
|
+
if (!/^[\da-f]{6}$/i.test(normalized)) return;
|
|
69
|
+
const number = Number.parseInt(normalized, 16);
|
|
70
|
+
const red = (number >> 16 & 255) / 255;
|
|
71
|
+
const green = (number >> 8 & 255) / 255;
|
|
72
|
+
const blue = (number & 255) / 255;
|
|
73
|
+
return UIColor.colorWithRedGreenBlueAlpha(red, green, blue, 1);
|
|
74
|
+
}
|
|
75
|
+
function colorFromStyle(value) {
|
|
76
|
+
if (value == null) return;
|
|
77
|
+
if (typeof value === "string") {
|
|
78
|
+
const hexColor = colorFromHex(value);
|
|
79
|
+
if (hexColor) return hexColor;
|
|
80
|
+
}
|
|
81
|
+
const color = processColor(value);
|
|
82
|
+
if (typeof color !== "number") return;
|
|
83
|
+
const alpha = (color >>> 24 & 255) / 255;
|
|
84
|
+
const red = (color >>> 16 & 255) / 255;
|
|
85
|
+
const green = (color >>> 8 & 255) / 255;
|
|
86
|
+
const blue = (color & 255) / 255;
|
|
87
|
+
return UIColor.colorWithRedGreenBlueAlpha(red, green, blue, alpha);
|
|
88
|
+
}
|
|
89
|
+
function fontFromStyle(style) {
|
|
90
|
+
if (typeof style?.fontSize !== "number") return;
|
|
91
|
+
if (style.fontWeight === "700" || style.fontWeight === "bold") return UIFont.boldSystemFontOfSize(style.fontSize);
|
|
92
|
+
return UIFont.systemFontOfSize(style.fontSize);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/elements/blur-view.tsx
|
|
97
|
+
function blurStyle(intensity, colorScheme) {
|
|
98
|
+
const scheme = colorScheme ?? "auto";
|
|
99
|
+
const level = intensity ?? "regular";
|
|
100
|
+
if (scheme === "light") switch (level) {
|
|
101
|
+
case "ultraThin": return UIBlurEffectStyle.SystemUltraThinMaterialLight;
|
|
102
|
+
case "thin": return UIBlurEffectStyle.SystemThinMaterialLight;
|
|
103
|
+
case "thick": return UIBlurEffectStyle.SystemThickMaterialLight;
|
|
104
|
+
case "chrome": return UIBlurEffectStyle.SystemChromeMaterialLight;
|
|
105
|
+
default: return UIBlurEffectStyle.SystemMaterialLight;
|
|
106
|
+
}
|
|
107
|
+
if (scheme === "dark") switch (level) {
|
|
108
|
+
case "ultraThin": return UIBlurEffectStyle.SystemUltraThinMaterialDark;
|
|
109
|
+
case "thin": return UIBlurEffectStyle.SystemThinMaterialDark;
|
|
110
|
+
case "thick": return UIBlurEffectStyle.SystemThickMaterialDark;
|
|
111
|
+
case "chrome": return UIBlurEffectStyle.SystemChromeMaterialDark;
|
|
112
|
+
default: return UIBlurEffectStyle.SystemMaterialDark;
|
|
113
|
+
}
|
|
114
|
+
switch (level) {
|
|
115
|
+
case "ultraThin": return UIBlurEffectStyle.SystemUltraThinMaterial;
|
|
116
|
+
case "thin": return UIBlurEffectStyle.SystemThinMaterial;
|
|
117
|
+
case "thick": return UIBlurEffectStyle.SystemThickMaterial;
|
|
118
|
+
case "chrome": return UIBlurEffectStyle.SystemChromeMaterial;
|
|
119
|
+
default: return UIBlurEffectStyle.SystemMaterial;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function createEffectHost(effect) {
|
|
123
|
+
const rootView = UIVisualEffectView.alloc().initWithEffect(effect);
|
|
124
|
+
rootView.backgroundColor = UIColor.clearColor;
|
|
125
|
+
rootView.contentView.backgroundColor = UIColor.clearColor;
|
|
126
|
+
rootView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
|
|
127
|
+
rootView.contentView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
|
|
128
|
+
return {
|
|
129
|
+
rootView,
|
|
130
|
+
childrenView: rootView.contentView
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function applyContainerStyle(view, style) {
|
|
134
|
+
const borderRadius = style?.borderRadius;
|
|
135
|
+
if (typeof borderRadius === "number") view.layer.cornerRadius = borderRadius;
|
|
136
|
+
view.clipsToBounds = style?.overflow === "hidden" || typeof borderRadius === "number";
|
|
137
|
+
}
|
|
138
|
+
function updateBlurEffect(view, props) {
|
|
139
|
+
view.effect = UIBlurEffect.effectWithStyle(blurStyle(props.intensity, props.colorScheme));
|
|
140
|
+
}
|
|
141
|
+
const BlurView = ensureNativeScript().defineUIKitContainer({
|
|
142
|
+
name: "BlurView",
|
|
143
|
+
layout: {
|
|
144
|
+
sizing: "fill",
|
|
145
|
+
defaultSize: {
|
|
146
|
+
width: 0,
|
|
147
|
+
height: 0
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
create() {
|
|
151
|
+
return createEffectHost(UIBlurEffect.effectWithStyle(UIBlurEffectStyle.SystemMaterial));
|
|
152
|
+
},
|
|
153
|
+
update(view, props, _previousProps, ctx) {
|
|
154
|
+
updateBlurEffect(view.rootView, props);
|
|
155
|
+
applyContainerStyle(view.rootView, styleFromProps(props.style));
|
|
156
|
+
ctx?.invalidateLayout();
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/elements/button-state.ts
|
|
162
|
+
function buttonDisabled(disabled, loading) {
|
|
163
|
+
return disabled || loading;
|
|
164
|
+
}
|
|
165
|
+
function buttonOpacity(options) {
|
|
166
|
+
if (buttonDisabled(options.disabled, options.loading)) return .45;
|
|
167
|
+
if (!options.pressed) return 1;
|
|
168
|
+
return Math.min(1, Math.max(0, options.activeOpacity));
|
|
169
|
+
}
|
|
170
|
+
function buttonAccessibilityState(state, disabled, loading) {
|
|
171
|
+
return {
|
|
172
|
+
...state,
|
|
173
|
+
disabled: buttonDisabled(disabled, loading),
|
|
174
|
+
busy: loading
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/elements/glass-shared.ts
|
|
180
|
+
function glassStyleValue(style) {
|
|
181
|
+
return typeof style === "object" ? style.style : style ?? "regular";
|
|
182
|
+
}
|
|
183
|
+
function glassEffect(style) {
|
|
184
|
+
if (style === "none") return null;
|
|
185
|
+
return UIGlassEffect.effectWithStyle(style === "clear" ? UIGlassEffectStyle.Clear : UIGlassEffectStyle.Regular);
|
|
186
|
+
}
|
|
187
|
+
function createGlassHost(effect) {
|
|
188
|
+
const rootView = UIVisualEffectView.alloc().initWithEffect(effect);
|
|
189
|
+
const childrenView = UIView.new();
|
|
190
|
+
rootView.backgroundColor = UIColor.clearColor;
|
|
191
|
+
rootView.contentView.backgroundColor = UIColor.clearColor;
|
|
192
|
+
childrenView.backgroundColor = UIColor.clearColor;
|
|
193
|
+
rootView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
|
|
194
|
+
rootView.contentView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
|
|
195
|
+
childrenView.translatesAutoresizingMaskIntoConstraints = false;
|
|
196
|
+
rootView.contentView.addSubview(childrenView);
|
|
197
|
+
const constraints = {
|
|
198
|
+
top: childrenView.topAnchor.constraintEqualToAnchorConstant(rootView.contentView.topAnchor, 0),
|
|
199
|
+
right: rootView.contentView.rightAnchor.constraintEqualToAnchorConstant(childrenView.rightAnchor, 0),
|
|
200
|
+
bottom: rootView.contentView.bottomAnchor.constraintEqualToAnchorConstant(childrenView.bottomAnchor, 0),
|
|
201
|
+
left: childrenView.leftAnchor.constraintEqualToAnchorConstant(rootView.contentView.leftAnchor, 0)
|
|
202
|
+
};
|
|
203
|
+
NSLayoutConstraint.activateConstraints([
|
|
204
|
+
constraints.top,
|
|
205
|
+
constraints.right,
|
|
206
|
+
constraints.bottom,
|
|
207
|
+
constraints.left
|
|
208
|
+
]);
|
|
209
|
+
return {
|
|
210
|
+
rootView,
|
|
211
|
+
childrenView
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function applyGlassShape(view, style) {
|
|
215
|
+
const radius = typeof style?.cornerRadius === "number" ? style.cornerRadius : 0;
|
|
216
|
+
view.layer.cornerRadius = radius;
|
|
217
|
+
view.contentView.layer.cornerRadius = radius;
|
|
218
|
+
view.layer.cornerCurve = kCACornerCurveContinuous;
|
|
219
|
+
view.contentView.layer.cornerCurve = kCACornerCurveContinuous;
|
|
220
|
+
view.clipsToBounds = radius > 0;
|
|
221
|
+
view.contentView.clipsToBounds = radius > 0;
|
|
222
|
+
view.layer.masksToBounds = radius > 0;
|
|
223
|
+
view.contentView.layer.masksToBounds = radius > 0;
|
|
224
|
+
view.layer.borderWidth = typeof style?.borderWidth === "number" ? style.borderWidth : 0;
|
|
225
|
+
const borderColor = colorFromStyle(style?.borderColor);
|
|
226
|
+
view.layer.borderColor = borderColor?.CGColor ?? null;
|
|
227
|
+
}
|
|
228
|
+
function updateGlassEffect(view, props) {
|
|
229
|
+
const style = glassStyleValue(props.glassEffectStyle);
|
|
230
|
+
const effect = glassEffect(style);
|
|
231
|
+
if (style !== "none") {
|
|
232
|
+
const tintColor = props.tintColor ? colorFromHex(props.tintColor) : void 0;
|
|
233
|
+
const glass = effect;
|
|
234
|
+
glass.interactive = props.isInteractive ?? false;
|
|
235
|
+
if (tintColor) glass.tintColor = tintColor;
|
|
236
|
+
}
|
|
237
|
+
if (typeof props.glassEffectStyle === "object" && props.glassEffectStyle.animate) UIView.animateWithDurationAnimations(props.glassEffectStyle.animationDuration ?? .35, () => {
|
|
238
|
+
view.effect = effect;
|
|
239
|
+
});
|
|
240
|
+
else view.effect = effect;
|
|
241
|
+
}
|
|
242
|
+
function updateGlassContainerEffect(view, spacing) {
|
|
243
|
+
const effect = UIGlassContainerEffect.new();
|
|
244
|
+
effect.spacing = spacing ?? 0;
|
|
245
|
+
view.effect = effect;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/elements/glass-view.tsx
|
|
250
|
+
const GlassView = ensureNativeScript().defineUIKitContainer({
|
|
251
|
+
name: "GlassView",
|
|
252
|
+
layout: {
|
|
253
|
+
sizing: "fill",
|
|
254
|
+
defaultSize: {
|
|
255
|
+
width: 0,
|
|
256
|
+
height: 0
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
create() {
|
|
260
|
+
return createGlassHost(glassEffect("regular"));
|
|
261
|
+
},
|
|
262
|
+
update(view, props, _previousProps, ctx) {
|
|
263
|
+
updateGlassEffect(view.rootView, props);
|
|
264
|
+
applyGlassShape(view.rootView, props.glassStyle);
|
|
265
|
+
ctx?.invalidateLayout();
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/elements/button.tsx
|
|
271
|
+
const sizeStyles = {
|
|
272
|
+
small: {
|
|
273
|
+
minHeight: 28,
|
|
274
|
+
minWidth: 28,
|
|
275
|
+
paddingHorizontal: 10
|
|
276
|
+
},
|
|
277
|
+
regular: {
|
|
278
|
+
minHeight: 36,
|
|
279
|
+
minWidth: 36,
|
|
280
|
+
paddingHorizontal: 14
|
|
281
|
+
},
|
|
282
|
+
large: {
|
|
283
|
+
minHeight: 44,
|
|
284
|
+
minWidth: 44,
|
|
285
|
+
paddingHorizontal: 18
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
const labelSizeStyles = {
|
|
289
|
+
small: { fontSize: 13 },
|
|
290
|
+
regular: { fontSize: 15 },
|
|
291
|
+
large: { fontSize: 17 }
|
|
292
|
+
};
|
|
293
|
+
const glassCornerRadius = {
|
|
294
|
+
small: 8,
|
|
295
|
+
regular: 10,
|
|
296
|
+
large: 12
|
|
297
|
+
};
|
|
298
|
+
function resolveStyle$2(style, state) {
|
|
299
|
+
return typeof style === "function" ? style(state) : style;
|
|
300
|
+
}
|
|
301
|
+
function ButtonContent({ icon, label, labelStyle, loading, size, variant }) {
|
|
302
|
+
const indicatorColor = variant === "primary" ? "#ffffff" : PlatformColor("systemBlue");
|
|
303
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [loading ? /* @__PURE__ */ jsx(ActivityIndicator, {
|
|
304
|
+
accessibilityElementsHidden: true,
|
|
305
|
+
color: indicatorColor,
|
|
306
|
+
size: "small"
|
|
307
|
+
}) : icon ? /* @__PURE__ */ jsx(View, {
|
|
308
|
+
accessibilityElementsHidden: true,
|
|
309
|
+
children: icon
|
|
310
|
+
}) : null, label ? /* @__PURE__ */ jsx(Text, {
|
|
311
|
+
numberOfLines: 1,
|
|
312
|
+
style: [
|
|
313
|
+
styles$3.label,
|
|
314
|
+
labelSizeStyles[size],
|
|
315
|
+
variant ? labelVariantStyles[variant] : styles$3.glassLabel,
|
|
316
|
+
labelStyle
|
|
317
|
+
],
|
|
318
|
+
children: label
|
|
319
|
+
}) : null] });
|
|
320
|
+
}
|
|
321
|
+
function Button({ accessibilityRole = "button", accessibilityState, activeOpacity = .2, disabled = false, icon, label, labelStyle, loading = false, size = "regular", style, variant = "primary",...props }) {
|
|
322
|
+
const inactive = buttonDisabled(disabled, loading);
|
|
323
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
324
|
+
...props,
|
|
325
|
+
accessibilityRole,
|
|
326
|
+
accessibilityState: buttonAccessibilityState(accessibilityState, disabled, loading),
|
|
327
|
+
disabled: inactive,
|
|
328
|
+
style: (state) => [
|
|
329
|
+
styles$3.button,
|
|
330
|
+
sizeStyles[size],
|
|
331
|
+
buttonVariantStyles[variant],
|
|
332
|
+
resolveStyle$2(style, state),
|
|
333
|
+
{ opacity: buttonOpacity({
|
|
334
|
+
...state,
|
|
335
|
+
disabled,
|
|
336
|
+
loading,
|
|
337
|
+
activeOpacity
|
|
338
|
+
}) }
|
|
339
|
+
],
|
|
340
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
341
|
+
pointerEvents: "none",
|
|
342
|
+
style: styles$3.content,
|
|
343
|
+
children: /* @__PURE__ */ jsx(ButtonContent, {
|
|
344
|
+
icon,
|
|
345
|
+
label,
|
|
346
|
+
labelStyle,
|
|
347
|
+
loading,
|
|
348
|
+
size,
|
|
349
|
+
variant
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
function GlassButton({ accessibilityRole = "button", accessibilityState, activeOpacity = .2, disabled = false, glassEffectStyle, glassStyle, icon, label, labelStyle, loading = false, size = "regular", style, tintColor,...props }) {
|
|
355
|
+
const inactive = buttonDisabled(disabled, loading);
|
|
356
|
+
return /* @__PURE__ */ jsxs(Pressable, {
|
|
357
|
+
...props,
|
|
358
|
+
accessibilityRole,
|
|
359
|
+
accessibilityState: buttonAccessibilityState(accessibilityState, disabled, loading),
|
|
360
|
+
disabled: inactive,
|
|
361
|
+
style: (state) => [
|
|
362
|
+
styles$3.button,
|
|
363
|
+
sizeStyles[size],
|
|
364
|
+
styles$3.glassButton,
|
|
365
|
+
resolveStyle$2(style, state),
|
|
366
|
+
{ opacity: buttonOpacity({
|
|
367
|
+
...state,
|
|
368
|
+
disabled,
|
|
369
|
+
loading,
|
|
370
|
+
activeOpacity
|
|
371
|
+
}) }
|
|
372
|
+
],
|
|
373
|
+
children: [/* @__PURE__ */ jsx(View, {
|
|
374
|
+
pointerEvents: "none",
|
|
375
|
+
style: styles$3.glassBackground,
|
|
376
|
+
children: /* @__PURE__ */ jsx(GlassView, {
|
|
377
|
+
glassEffectStyle,
|
|
378
|
+
glassStyle: {
|
|
379
|
+
cornerRadius: glassCornerRadius[size],
|
|
380
|
+
...glassStyle
|
|
381
|
+
},
|
|
382
|
+
isInteractive: false,
|
|
383
|
+
style: styles$3.glass,
|
|
384
|
+
tintColor
|
|
385
|
+
})
|
|
386
|
+
}), /* @__PURE__ */ jsx(View, {
|
|
387
|
+
pointerEvents: "none",
|
|
388
|
+
style: styles$3.content,
|
|
389
|
+
children: /* @__PURE__ */ jsx(ButtonContent, {
|
|
390
|
+
icon,
|
|
391
|
+
label,
|
|
392
|
+
labelStyle,
|
|
393
|
+
loading,
|
|
394
|
+
size
|
|
395
|
+
})
|
|
396
|
+
})]
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
const styles$3 = StyleSheet.create({
|
|
400
|
+
button: {
|
|
401
|
+
alignItems: "center",
|
|
402
|
+
borderRadius: 10,
|
|
403
|
+
justifyContent: "center"
|
|
404
|
+
},
|
|
405
|
+
glassButton: { backgroundColor: "transparent" },
|
|
406
|
+
glass: { flex: 1 },
|
|
407
|
+
glassBackground: {
|
|
408
|
+
bottom: 0,
|
|
409
|
+
left: 0,
|
|
410
|
+
position: "absolute",
|
|
411
|
+
right: 0,
|
|
412
|
+
top: 0
|
|
413
|
+
},
|
|
414
|
+
content: {
|
|
415
|
+
alignItems: "center",
|
|
416
|
+
flexDirection: "row",
|
|
417
|
+
gap: 7,
|
|
418
|
+
justifyContent: "center"
|
|
419
|
+
},
|
|
420
|
+
label: { fontWeight: "600" },
|
|
421
|
+
glassLabel: { color: PlatformColor("label") }
|
|
422
|
+
});
|
|
423
|
+
const buttonVariantStyles = StyleSheet.create({
|
|
424
|
+
primary: { backgroundColor: PlatformColor("systemBlue") },
|
|
425
|
+
secondary: { backgroundColor: PlatformColor("secondarySystemFill") },
|
|
426
|
+
plain: { backgroundColor: "transparent" }
|
|
427
|
+
});
|
|
428
|
+
const labelVariantStyles = StyleSheet.create({
|
|
429
|
+
primary: { color: "#ffffff" },
|
|
430
|
+
secondary: { color: PlatformColor("label") },
|
|
431
|
+
plain: { color: PlatformColor("systemBlue") }
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/elements/symbol.tsx
|
|
436
|
+
function symbolWeight(weight) {
|
|
437
|
+
switch (weight) {
|
|
438
|
+
case "ultraLight": return UIImageSymbolWeight.UltraLight;
|
|
439
|
+
case "thin": return UIImageSymbolWeight.Thin;
|
|
440
|
+
case "light": return UIImageSymbolWeight.Light;
|
|
441
|
+
case "medium": return UIImageSymbolWeight.Medium;
|
|
442
|
+
case "semibold": return UIImageSymbolWeight.Semibold;
|
|
443
|
+
case "bold": return UIImageSymbolWeight.Bold;
|
|
444
|
+
case "heavy": return UIImageSymbolWeight.Heavy;
|
|
445
|
+
case "black": return UIImageSymbolWeight.Black;
|
|
446
|
+
default: return UIImageSymbolWeight.Regular;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function symbolScale(scale) {
|
|
450
|
+
if (scale === "small") return UIImageSymbolScale.Small;
|
|
451
|
+
if (scale === "large") return UIImageSymbolScale.Large;
|
|
452
|
+
return UIImageSymbolScale.Medium;
|
|
453
|
+
}
|
|
454
|
+
function symbolConfiguration(props, style) {
|
|
455
|
+
const size = props.size ?? style?.fontSize ?? 17;
|
|
456
|
+
return UIImageSymbolConfiguration.configurationWithPointSizeWeightScale(size, symbolWeight(props.weight), symbolScale(props.scale));
|
|
457
|
+
}
|
|
458
|
+
function symbolImage(name, configuration) {
|
|
459
|
+
if (configuration) return UIImage.systemImageNamedWithConfiguration(name, configuration);
|
|
460
|
+
return UIImage.systemImageNamed(name);
|
|
461
|
+
}
|
|
462
|
+
const SFSymbol = ensureNativeScript().defineUIKitView({
|
|
463
|
+
name: "SFSymbol",
|
|
464
|
+
layout: {
|
|
465
|
+
sizing: "intrinsic",
|
|
466
|
+
defaultSize: {
|
|
467
|
+
width: 17,
|
|
468
|
+
height: 17
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
create() {
|
|
472
|
+
const imageView = UIImageView.new();
|
|
473
|
+
imageView.contentMode = UIViewContentMode.ScaleAspectFit;
|
|
474
|
+
return imageView;
|
|
475
|
+
},
|
|
476
|
+
update(imageView, props, _previousProps, ctx) {
|
|
477
|
+
const style = styleFromProps(props.style);
|
|
478
|
+
const configuration = symbolConfiguration(props, style);
|
|
479
|
+
imageView.image = symbolImage(props.symbol, configuration);
|
|
480
|
+
imageView.tintColor = colorFromStyle(props.color) ?? colorFromStyle(style?.tintColor) ?? colorFromStyle(style?.color) ?? UIColor.labelColor;
|
|
481
|
+
ctx?.invalidateLayout();
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
//#endregion
|
|
486
|
+
//#region src/elements/conversation.tsx
|
|
487
|
+
const ConversationContext = createContext(null);
|
|
488
|
+
const scrollEndThreshold = 48;
|
|
489
|
+
function useConversation() {
|
|
490
|
+
const context = useContext(ConversationContext);
|
|
491
|
+
if (!context) throw new Error("Conversation elements must be rendered inside <Conversation>");
|
|
492
|
+
return context;
|
|
493
|
+
}
|
|
494
|
+
function Conversation({ children, defaultFollowOutput = true, followOutput, onFollowOutputChange, style,...props }) {
|
|
495
|
+
const controlled = followOutput !== void 0;
|
|
496
|
+
const generation = useRef(0);
|
|
497
|
+
const [internalFollowing, setInternalFollowing] = useState(defaultFollowOutput);
|
|
498
|
+
const [isAtBottom, setIsAtBottom] = useState(true);
|
|
499
|
+
const [followGeneration, setFollowGeneration] = useState(0);
|
|
500
|
+
const following = controlled ? followOutput : internalFollowing;
|
|
501
|
+
const setFollowing = useCallback((value) => {
|
|
502
|
+
if (!controlled) setInternalFollowing(value);
|
|
503
|
+
onFollowOutputChange?.(value);
|
|
504
|
+
}, [controlled, onFollowOutputChange]);
|
|
505
|
+
const updateAtBottom = useCallback((value) => {
|
|
506
|
+
setIsAtBottom(value);
|
|
507
|
+
if (following !== value) setFollowing(value);
|
|
508
|
+
}, [following, setFollowing]);
|
|
509
|
+
const requestFollow = useCallback(() => {
|
|
510
|
+
generation.current += 1;
|
|
511
|
+
setFollowGeneration(generation.current);
|
|
512
|
+
setFollowing(true);
|
|
513
|
+
}, [setFollowing]);
|
|
514
|
+
const context = useMemo(() => ({
|
|
515
|
+
followGeneration,
|
|
516
|
+
following,
|
|
517
|
+
isAtBottom,
|
|
518
|
+
updateAtBottom,
|
|
519
|
+
requestFollow
|
|
520
|
+
}), [
|
|
521
|
+
followGeneration,
|
|
522
|
+
following,
|
|
523
|
+
isAtBottom,
|
|
524
|
+
updateAtBottom,
|
|
525
|
+
requestFollow
|
|
526
|
+
]);
|
|
527
|
+
return /* @__PURE__ */ jsx(ConversationContext.Provider, {
|
|
528
|
+
value: context,
|
|
529
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
530
|
+
...props,
|
|
531
|
+
style: [styles$2.conversation, style],
|
|
532
|
+
children
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
function ConversationContent({ contentContainerStyle, data, keyboardShouldPersistTaps = "handled", onContentSizeChange, onScroll, renderItem, scrollEventThrottle = 16,...props }) {
|
|
537
|
+
const context = useConversation();
|
|
538
|
+
const list = useRef(null);
|
|
539
|
+
const following = useRef(context.following);
|
|
540
|
+
const previousHeight = useRef(0);
|
|
541
|
+
const previousFollowGeneration = useRef(context.followGeneration);
|
|
542
|
+
following.current = context.following;
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
if (context.following && context.followGeneration > previousFollowGeneration.current) {
|
|
545
|
+
previousFollowGeneration.current = context.followGeneration;
|
|
546
|
+
list.current?.scrollToEnd({ animated: true });
|
|
547
|
+
}
|
|
548
|
+
}, [context.followGeneration, context.following]);
|
|
549
|
+
const handleScroll = useCallback((event) => {
|
|
550
|
+
const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent;
|
|
551
|
+
const distance = contentSize.height - (contentOffset.y + layoutMeasurement.height);
|
|
552
|
+
context.updateAtBottom(distance <= scrollEndThreshold);
|
|
553
|
+
onScroll?.(event);
|
|
554
|
+
}, [context, onScroll]);
|
|
555
|
+
const handleContentSizeChange = useCallback((width, height) => {
|
|
556
|
+
const newFollowRequested = context.followGeneration > previousFollowGeneration.current;
|
|
557
|
+
const shouldScroll = following.current && (previousHeight.current === 0 || height > previousHeight.current || newFollowRequested);
|
|
558
|
+
previousHeight.current = height;
|
|
559
|
+
previousFollowGeneration.current = context.followGeneration;
|
|
560
|
+
if (shouldScroll) list.current?.scrollToEnd({ animated: true });
|
|
561
|
+
onContentSizeChange?.(width, height);
|
|
562
|
+
}, [context.followGeneration, onContentSizeChange]);
|
|
563
|
+
return /* @__PURE__ */ jsx(FlatList, {
|
|
564
|
+
...props,
|
|
565
|
+
data,
|
|
566
|
+
keyboardShouldPersistTaps,
|
|
567
|
+
onContentSizeChange: handleContentSizeChange,
|
|
568
|
+
onScroll: handleScroll,
|
|
569
|
+
ref: list,
|
|
570
|
+
renderItem,
|
|
571
|
+
scrollEventThrottle,
|
|
572
|
+
style: [styles$2.content, props.style],
|
|
573
|
+
contentContainerStyle: [styles$2.contentContainer, contentContainerStyle]
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
function ConversationEmptyState({ children, description = "Start a conversation to see messages here.", descriptionStyle, icon, style, title = "No messages yet", titleStyle,...props }) {
|
|
577
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
578
|
+
...props,
|
|
579
|
+
style: [styles$2.emptyState, style],
|
|
580
|
+
children: [
|
|
581
|
+
icon ? /* @__PURE__ */ jsx(View, {
|
|
582
|
+
accessibilityElementsHidden: true,
|
|
583
|
+
style: styles$2.emptyIcon,
|
|
584
|
+
children: icon
|
|
585
|
+
}) : null,
|
|
586
|
+
/* @__PURE__ */ jsx(Text, {
|
|
587
|
+
style: [styles$2.emptyTitle, titleStyle],
|
|
588
|
+
children: title
|
|
589
|
+
}),
|
|
590
|
+
/* @__PURE__ */ jsx(Text, {
|
|
591
|
+
style: [styles$2.emptyDescription, descriptionStyle],
|
|
592
|
+
children: description
|
|
593
|
+
}),
|
|
594
|
+
children
|
|
595
|
+
]
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
function ConversationScrollButton({ accessibilityLabel = "Scroll to latest message", activeOpacity = .2, children, onPress, style,...props }) {
|
|
599
|
+
const context = useConversation();
|
|
600
|
+
if (context.isAtBottom) return null;
|
|
601
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
602
|
+
...props,
|
|
603
|
+
accessibilityLabel,
|
|
604
|
+
accessibilityRole: "button",
|
|
605
|
+
onPress: () => {
|
|
606
|
+
context.requestFollow();
|
|
607
|
+
onPress?.();
|
|
608
|
+
},
|
|
609
|
+
style: (state) => [
|
|
610
|
+
styles$2.scrollButton,
|
|
611
|
+
resolveStyle$1(style, state),
|
|
612
|
+
state.pressed && { opacity: activeOpacity }
|
|
613
|
+
],
|
|
614
|
+
children: children ?? /* @__PURE__ */ jsx(SFSymbol, {
|
|
615
|
+
color: PlatformColor("systemBlue"),
|
|
616
|
+
size: 16,
|
|
617
|
+
symbol: "arrow.down"
|
|
618
|
+
})
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function resolveStyle$1(style, state) {
|
|
622
|
+
return typeof style === "function" ? style(state) : style;
|
|
623
|
+
}
|
|
624
|
+
const styles$2 = StyleSheet.create({
|
|
625
|
+
conversation: {
|
|
626
|
+
flex: 1,
|
|
627
|
+
minHeight: 0,
|
|
628
|
+
position: "relative"
|
|
629
|
+
},
|
|
630
|
+
content: { flex: 1 },
|
|
631
|
+
contentContainer: {
|
|
632
|
+
gap: 16,
|
|
633
|
+
padding: 16
|
|
634
|
+
},
|
|
635
|
+
emptyState: {
|
|
636
|
+
alignItems: "center",
|
|
637
|
+
alignSelf: "center",
|
|
638
|
+
gap: 8,
|
|
639
|
+
justifyContent: "center",
|
|
640
|
+
maxWidth: 320,
|
|
641
|
+
padding: 32
|
|
642
|
+
},
|
|
643
|
+
emptyIcon: { marginBottom: 8 },
|
|
644
|
+
emptyTitle: {
|
|
645
|
+
color: PlatformColor("label"),
|
|
646
|
+
fontSize: 17,
|
|
647
|
+
fontWeight: "600",
|
|
648
|
+
textAlign: "center"
|
|
649
|
+
},
|
|
650
|
+
emptyDescription: {
|
|
651
|
+
color: PlatformColor("secondaryLabel"),
|
|
652
|
+
fontSize: 15,
|
|
653
|
+
textAlign: "center"
|
|
654
|
+
},
|
|
655
|
+
scrollButton: {
|
|
656
|
+
alignItems: "center",
|
|
657
|
+
backgroundColor: PlatformColor("secondarySystemBackground"),
|
|
658
|
+
borderColor: PlatformColor("separator"),
|
|
659
|
+
borderRadius: 18,
|
|
660
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
661
|
+
bottom: 16,
|
|
662
|
+
height: 36,
|
|
663
|
+
justifyContent: "center",
|
|
664
|
+
position: "absolute",
|
|
665
|
+
right: 16,
|
|
666
|
+
width: 36
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
//#endregion
|
|
671
|
+
//#region src/elements/glass-container.tsx
|
|
672
|
+
const GlassContainer = ensureNativeScript().defineUIKitContainer({
|
|
673
|
+
name: "GlassContainer",
|
|
674
|
+
layout: {
|
|
675
|
+
sizing: "fill",
|
|
676
|
+
defaultSize: {
|
|
677
|
+
width: 0,
|
|
678
|
+
height: 0
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
create() {
|
|
682
|
+
const host = createGlassHost(UIGlassContainerEffect.new());
|
|
683
|
+
updateGlassContainerEffect(host.rootView, void 0);
|
|
684
|
+
return host;
|
|
685
|
+
},
|
|
686
|
+
update(view, props, _previousProps, ctx) {
|
|
687
|
+
updateGlassContainerEffect(view.rootView, props.spacing);
|
|
688
|
+
applyGlassShape(view.rootView, props.glassStyle);
|
|
689
|
+
ctx?.invalidateLayout();
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
//#endregion
|
|
694
|
+
//#region src/elements/label.tsx
|
|
695
|
+
function labelText(props) {
|
|
696
|
+
return props.text ?? textFromChildren(props.children) ?? "";
|
|
697
|
+
}
|
|
698
|
+
function defaultLabelColor(tone) {
|
|
699
|
+
if (tone === "secondary") return UIColor.secondaryLabelColor;
|
|
700
|
+
if (tone === "tertiary") return UIColor.tertiaryLabelColor;
|
|
701
|
+
return UIColor.labelColor;
|
|
702
|
+
}
|
|
703
|
+
const Label = ensureNativeScript().defineUIKitView({
|
|
704
|
+
name: "Label",
|
|
705
|
+
layout: {
|
|
706
|
+
sizing: "intrinsic",
|
|
707
|
+
defaultSize: {
|
|
708
|
+
width: 1,
|
|
709
|
+
height: 24
|
|
710
|
+
}
|
|
711
|
+
},
|
|
712
|
+
create() {
|
|
713
|
+
const label = UILabel.new();
|
|
714
|
+
label.adjustsFontForContentSizeCategory = true;
|
|
715
|
+
return label;
|
|
716
|
+
},
|
|
717
|
+
update(label, props, _previousProps, ctx) {
|
|
718
|
+
const style = styleFromProps(props.style);
|
|
719
|
+
label.text = labelText(props);
|
|
720
|
+
label.textColor = colorFromStyle(style?.color) ?? defaultLabelColor(props.tone);
|
|
721
|
+
label.font = fontFromStyle(style) ?? UIFont.preferredFontForTextStyle(UIFontTextStyleBody);
|
|
722
|
+
label.numberOfLines = props.numberOfLines ?? 0;
|
|
723
|
+
if (style?.textAlign === "center") label.textAlignment = NSTextAlignment.Center;
|
|
724
|
+
else if (style?.textAlign === "right") label.textAlignment = NSTextAlignment.Right;
|
|
725
|
+
else label.textAlignment = NSTextAlignment.Left;
|
|
726
|
+
ctx?.invalidateLayout();
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region src/elements/message.tsx
|
|
732
|
+
function Message({ children, from = "assistant", style,...props }) {
|
|
733
|
+
return /* @__PURE__ */ jsx(View, {
|
|
734
|
+
...props,
|
|
735
|
+
style: [
|
|
736
|
+
styles$1.message,
|
|
737
|
+
from === "user" ? styles$1.userMessage : styles$1.assistantMessage,
|
|
738
|
+
style
|
|
739
|
+
],
|
|
740
|
+
children
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
function MessageContent({ children, style,...props }) {
|
|
744
|
+
return /* @__PURE__ */ jsx(View, {
|
|
745
|
+
...props,
|
|
746
|
+
style: [styles$1.content, style],
|
|
747
|
+
children
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
function MessageText({ style,...props }) {
|
|
751
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
752
|
+
...props,
|
|
753
|
+
style: [styles$1.text, style]
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
function MessageStatus({ label, showSymbol = true, status, style,...props }) {
|
|
757
|
+
const display = messageStatusDisplay(status);
|
|
758
|
+
const color = PlatformColor(display.color);
|
|
759
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
760
|
+
style: styles$1.status,
|
|
761
|
+
children: [showSymbol ? /* @__PURE__ */ jsx(SFSymbol, {
|
|
762
|
+
color,
|
|
763
|
+
size: 12,
|
|
764
|
+
symbol: display.symbol
|
|
765
|
+
}) : null, /* @__PURE__ */ jsx(Text, {
|
|
766
|
+
...props,
|
|
767
|
+
style: [
|
|
768
|
+
styles$1.statusText,
|
|
769
|
+
{ color },
|
|
770
|
+
style
|
|
771
|
+
],
|
|
772
|
+
children: label ?? display.label
|
|
773
|
+
})]
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
function MessageActions({ children, style,...props }) {
|
|
777
|
+
return /* @__PURE__ */ jsx(View, {
|
|
778
|
+
...props,
|
|
779
|
+
style: [styles$1.actions, style],
|
|
780
|
+
children
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
const styles$1 = StyleSheet.create({
|
|
784
|
+
message: {
|
|
785
|
+
gap: 6,
|
|
786
|
+
maxWidth: "85%"
|
|
787
|
+
},
|
|
788
|
+
userMessage: { alignSelf: "flex-end" },
|
|
789
|
+
assistantMessage: { alignSelf: "stretch" },
|
|
790
|
+
content: {
|
|
791
|
+
backgroundColor: PlatformColor("secondarySystemFill"),
|
|
792
|
+
borderRadius: 16,
|
|
793
|
+
paddingHorizontal: 14,
|
|
794
|
+
paddingVertical: 10
|
|
795
|
+
},
|
|
796
|
+
text: {
|
|
797
|
+
color: PlatformColor("label"),
|
|
798
|
+
fontSize: 15,
|
|
799
|
+
lineHeight: 21
|
|
800
|
+
},
|
|
801
|
+
status: {
|
|
802
|
+
alignItems: "center",
|
|
803
|
+
flexDirection: "row",
|
|
804
|
+
gap: 5
|
|
805
|
+
},
|
|
806
|
+
statusText: {
|
|
807
|
+
fontSize: 12,
|
|
808
|
+
fontWeight: "500"
|
|
809
|
+
},
|
|
810
|
+
actions: {
|
|
811
|
+
flexDirection: "row",
|
|
812
|
+
flexWrap: "wrap",
|
|
813
|
+
gap: 8
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
//#endregion
|
|
818
|
+
//#region src/elements/prompt-input.tsx
|
|
819
|
+
const PromptInputContext = createContext(null);
|
|
820
|
+
function usePromptInput() {
|
|
821
|
+
const context = useContext(PromptInputContext);
|
|
822
|
+
if (!context) throw new Error("Prompt input elements must be rendered inside <PromptInput>");
|
|
823
|
+
return context;
|
|
824
|
+
}
|
|
825
|
+
function PromptInput({ children, defaultValue = "", disabled = false, onChangeText, onSubmit, status, style, value,...props }) {
|
|
826
|
+
const controlled = value !== void 0;
|
|
827
|
+
const [internalText, setInternalText] = useState(defaultValue);
|
|
828
|
+
const text = controlled ? value : internalText;
|
|
829
|
+
const setText = useCallback((nextText) => {
|
|
830
|
+
if (!controlled) setInternalText(nextText);
|
|
831
|
+
onChangeText?.(nextText);
|
|
832
|
+
}, [controlled, onChangeText]);
|
|
833
|
+
const submit = useCallback(() => {
|
|
834
|
+
if (disabled) return;
|
|
835
|
+
onSubmit?.({ text });
|
|
836
|
+
}, [
|
|
837
|
+
disabled,
|
|
838
|
+
onSubmit,
|
|
839
|
+
text
|
|
840
|
+
]);
|
|
841
|
+
const context = useMemo(() => ({
|
|
842
|
+
disabled,
|
|
843
|
+
generating: promptStatusGenerating(status),
|
|
844
|
+
setText,
|
|
845
|
+
status,
|
|
846
|
+
submit,
|
|
847
|
+
text
|
|
848
|
+
}), [
|
|
849
|
+
disabled,
|
|
850
|
+
setText,
|
|
851
|
+
status,
|
|
852
|
+
submit,
|
|
853
|
+
text
|
|
854
|
+
]);
|
|
855
|
+
return /* @__PURE__ */ jsx(PromptInputContext.Provider, {
|
|
856
|
+
value: context,
|
|
857
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
858
|
+
...props,
|
|
859
|
+
style: [styles.input, style],
|
|
860
|
+
children
|
|
861
|
+
})
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
function PromptInputHeader({ children, style,...props }) {
|
|
865
|
+
return /* @__PURE__ */ jsx(View, {
|
|
866
|
+
...props,
|
|
867
|
+
style: [styles.header, style],
|
|
868
|
+
children
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
function PromptInputBody({ children, style,...props }) {
|
|
872
|
+
return /* @__PURE__ */ jsx(View, {
|
|
873
|
+
...props,
|
|
874
|
+
style: [styles.body, style],
|
|
875
|
+
children
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
function PromptInputFooter({ children, style,...props }) {
|
|
879
|
+
return /* @__PURE__ */ jsx(View, {
|
|
880
|
+
...props,
|
|
881
|
+
style: [styles.footer, style],
|
|
882
|
+
children
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
function PromptInputTools({ children, style,...props }) {
|
|
886
|
+
return /* @__PURE__ */ jsx(View, {
|
|
887
|
+
...props,
|
|
888
|
+
style: [styles.tools, style],
|
|
889
|
+
children
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
function PromptInputTextarea({ multiline = true, onChangeText, onSubmitEditing, placeholder = "Send a message", placeholderTextColor = PlatformColor("placeholderText"), returnKeyType = "send", style, submitOnEnter = !multiline, value,...props }) {
|
|
893
|
+
const context = usePromptInput();
|
|
894
|
+
const text = value !== void 0 ? value : context.text;
|
|
895
|
+
return /* @__PURE__ */ jsx(TextInput, {
|
|
896
|
+
...props,
|
|
897
|
+
editable: !context.disabled && props.editable !== false,
|
|
898
|
+
multiline,
|
|
899
|
+
onChangeText: (nextText) => {
|
|
900
|
+
context.setText(nextText);
|
|
901
|
+
onChangeText?.(nextText);
|
|
902
|
+
},
|
|
903
|
+
onSubmitEditing: (event) => {
|
|
904
|
+
onSubmitEditing?.(event);
|
|
905
|
+
if (submitOnEnter) context.submit();
|
|
906
|
+
},
|
|
907
|
+
placeholder,
|
|
908
|
+
placeholderTextColor,
|
|
909
|
+
returnKeyType,
|
|
910
|
+
style: [styles.textarea, style],
|
|
911
|
+
submitBehavior: multiline && !submitOnEnter ? "newline" : "submit",
|
|
912
|
+
value: text
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
function PromptInputSubmit({ accessibilityLabel, accessibilityState, activeOpacity = .2, children, disabled: disabledProp, generating, loading = false, onPress, status, style,...props }) {
|
|
916
|
+
const context = usePromptInput();
|
|
917
|
+
const resolvedStatus = status ?? context.status;
|
|
918
|
+
const resolvedGenerating = generating ?? loading ?? promptStatusGenerating(resolvedStatus);
|
|
919
|
+
const disabled = context.disabled || buttonDisabled(disabledProp === true, loading);
|
|
920
|
+
const resolvedChildren = typeof children === "function" ? children({ generating: resolvedGenerating }) : children;
|
|
921
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
922
|
+
...props,
|
|
923
|
+
accessibilityLabel: accessibilityLabel ?? promptStatusLabel(resolvedStatus, resolvedGenerating),
|
|
924
|
+
accessibilityRole: "button",
|
|
925
|
+
accessibilityState: {
|
|
926
|
+
...accessibilityState,
|
|
927
|
+
busy: resolvedGenerating,
|
|
928
|
+
disabled
|
|
929
|
+
},
|
|
930
|
+
disabled,
|
|
931
|
+
onPress: () => {
|
|
932
|
+
if (onPress) onPress({ text: context.text });
|
|
933
|
+
else context.submit();
|
|
934
|
+
},
|
|
935
|
+
style: (state) => [
|
|
936
|
+
styles.submit,
|
|
937
|
+
resolveStyle(style, state),
|
|
938
|
+
{ opacity: buttonOpacity({
|
|
939
|
+
...state,
|
|
940
|
+
disabled,
|
|
941
|
+
loading,
|
|
942
|
+
activeOpacity
|
|
943
|
+
}) }
|
|
944
|
+
],
|
|
945
|
+
children: resolvedChildren ?? /* @__PURE__ */ jsx(SFSymbol, {
|
|
946
|
+
color: "#ffffff",
|
|
947
|
+
size: 16,
|
|
948
|
+
symbol: promptStatusSymbol(resolvedStatus, resolvedGenerating),
|
|
949
|
+
weight: "semibold"
|
|
950
|
+
})
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
function resolveStyle(style, state) {
|
|
954
|
+
return typeof style === "function" ? style(state) : style;
|
|
955
|
+
}
|
|
956
|
+
const styles = StyleSheet.create({
|
|
957
|
+
input: {
|
|
958
|
+
backgroundColor: PlatformColor("secondarySystemBackground"),
|
|
959
|
+
borderColor: PlatformColor("separator"),
|
|
960
|
+
borderRadius: 18,
|
|
961
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
962
|
+
gap: 8,
|
|
963
|
+
padding: 10
|
|
964
|
+
},
|
|
965
|
+
header: { gap: 8 },
|
|
966
|
+
body: { gap: 8 },
|
|
967
|
+
footer: {
|
|
968
|
+
alignItems: "center",
|
|
969
|
+
flexDirection: "row",
|
|
970
|
+
gap: 8,
|
|
971
|
+
justifyContent: "space-between"
|
|
972
|
+
},
|
|
973
|
+
tools: {
|
|
974
|
+
alignItems: "center",
|
|
975
|
+
flexDirection: "row",
|
|
976
|
+
flex: 1,
|
|
977
|
+
flexWrap: "wrap",
|
|
978
|
+
gap: 8
|
|
979
|
+
},
|
|
980
|
+
textarea: {
|
|
981
|
+
color: PlatformColor("label"),
|
|
982
|
+
fontSize: 15,
|
|
983
|
+
minHeight: 40,
|
|
984
|
+
padding: 4
|
|
985
|
+
},
|
|
986
|
+
submit: {
|
|
987
|
+
alignItems: "center",
|
|
988
|
+
alignSelf: "flex-end",
|
|
989
|
+
backgroundColor: PlatformColor("systemBlue"),
|
|
990
|
+
borderRadius: 18,
|
|
991
|
+
height: 36,
|
|
992
|
+
justifyContent: "center",
|
|
993
|
+
minWidth: 36,
|
|
994
|
+
paddingHorizontal: 9
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
//#endregion
|
|
999
|
+
export { BlurView, Button, Conversation, ConversationContent, ConversationEmptyState, ConversationScrollButton, GlassButton, GlassContainer, GlassView, Label, Message, MessageActions, MessageContent, MessageStatus, MessageText, PromptInput, PromptInputBody, PromptInputFooter, PromptInputHeader, PromptInputSubmit, PromptInputTextarea, PromptInputTools, SFSymbol, messageStatusDisplay, promptStatusGenerating, promptStatusLabel, promptStatusSymbol, useConversation, usePromptInput };
|