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.
Files changed (57) hide show
  1. package/dist/ai.cjs +5 -4
  2. package/dist/ai.js +4 -3
  3. package/dist/app-storage-D8W4n8ey.cjs +39 -0
  4. package/dist/app-storage-Isi5Bo0R.js +34 -0
  5. package/dist/cli.cjs +149 -23
  6. package/dist/cli.d.cts +13 -0
  7. package/dist/cli.d.ts +13 -0
  8. package/dist/cli.js +149 -23
  9. package/dist/elements-DX_YUveu.d.ts +341 -0
  10. package/dist/elements-gEI8YGl1.d.cts +341 -0
  11. package/dist/elements.cjs +1031 -0
  12. package/dist/elements.d.cts +2 -0
  13. package/dist/elements.d.ts +2 -0
  14. package/dist/elements.js +999 -0
  15. package/dist/{files-BXVkPrPN.js → files-DErLhzCB.js} +5 -11
  16. package/dist/{files-DxaQ-Nv0.cjs → files-lMk-CpL_.cjs} +5 -11
  17. package/dist/files.cjs +1 -1
  18. package/dist/files.js +1 -1
  19. package/dist/schema.cjs +1 -1
  20. package/dist/schema.d.cts +1 -1
  21. package/dist/schema.d.ts +1 -1
  22. package/dist/schema.js +1 -1
  23. package/dist/secrets.cjs +146 -0
  24. package/dist/secrets.d.cts +14 -0
  25. package/dist/secrets.d.ts +14 -0
  26. package/dist/secrets.js +142 -0
  27. package/dist/{state-LssDgpff.cjs → state-Bm9GiRnU.cjs} +61 -47
  28. package/dist/{state-Dh3HLixb.js → state-D8Firo9w.js} +60 -41
  29. package/dist/state.cjs +3 -2
  30. package/dist/state.d.cts +1 -1
  31. package/dist/state.d.ts +1 -1
  32. package/dist/state.js +3 -2
  33. package/dist/window.d.cts +1 -1
  34. package/dist/window.d.ts +1 -1
  35. package/package.json +14 -11
  36. package/templates/basic/app/index.tsx +7 -129
  37. package/templates/foundation-models/app/index.tsx +100 -41
  38. package/templates/image-generation/app/index.tsx +2 -2
  39. package/templates/native/ios/Podfile.lock +6 -0
  40. package/templates/native/modules/bleam-runtime/ios/AIModule.swift +7 -8
  41. package/templates/native/package.json +6 -1
  42. package/templates/native/yarn.lock +5392 -3749
  43. package/templates/state/app/index.tsx +2 -2
  44. package/templates/text-generation/app/index.tsx +4 -4
  45. package/templates/updates/README.md +1 -1
  46. package/dist/native-sqlite-xcGdamRD.js +0 -64
  47. package/dist/native-sqlite-yQLD5s9i.cjs +0 -66
  48. package/dist/ui-1WepaMS4.d.cts +0 -92
  49. package/dist/ui-D7bRLYee.d.ts +0 -92
  50. package/dist/ui.cjs +0 -364
  51. package/dist/ui.d.cts +0 -2
  52. package/dist/ui.d.ts +0 -2
  53. package/dist/ui.js +0 -357
  54. /package/dist/{schema-B5BfdswF.js → schema-B7ELMpuI.js} +0 -0
  55. /package/dist/{schema-BnVZOXfu.cjs → schema-B7SLUBLN.cjs} +0 -0
  56. /package/dist/{schema-D5eImHxu.d.cts → schema-BWsDPc6c.d.cts} +0 -0
  57. /package/dist/{schema-SSjokbtw.d.ts → schema-DsXZBnvc.d.ts} +0 -0
@@ -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 };