bleam 0.0.13 → 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/files.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as DownloadTask, c as FileStat, d as PickOptions, f as RemoveOptions, i as DownloadProgress, l as FileType, m as files, n as DirectoryRef, o as FilePaths, p as WriteOptions, r as DownloadOptions, s as FileRef, t as CreateDirectoryOptions, u as PickFileType } from "./files-4ZEoAWiv.js";
1
+ import { a as DownloadTask, c as FileStat, d as PickOptions, f as RemoveOptions, i as DownloadProgress, l as FileType, m as files, n as DirectoryRef, o as FilePaths, p as WriteOptions, r as DownloadOptions, s as FileRef, t as CreateDirectoryOptions, u as PickFileType } from "./files-VrkQlKIT.js";
2
2
  export { CreateDirectoryOptions, DirectoryRef, DownloadOptions, DownloadProgress, DownloadTask, FilePaths, FileRef, FileStat, FileType, PickFileType, PickOptions, RemoveOptions, WriteOptions, files };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as HexColor, c as defineConfig, i as BleamUserInterfaceStyle, n as BleamConfig, o as appConfig, r as BleamInternalExpoConfig, s as createExpoConfig, t as BleamAppearance } from "./config-Cms0rvqg.js";
1
+ import { a as HexColor, c as defineConfig, i as BleamUserInterfaceStyle, n as BleamConfig, o as appConfig, r as BleamInternalExpoConfig, s as createExpoConfig, t as BleamAppearance } from "./config-Chi-flpJ.js";
2
2
  export { BleamAppearance, BleamConfig, BleamInternalExpoConfig, BleamUserInterfaceStyle, HexColor, appConfig, createExpoConfig, defineConfig };
package/dist/schema.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as array, C as SchemaOutput, D as StandardSchema, E as SchemaShape, F as number, I as object, L as schema, M as getFieldSchema, N as getValueAtPath, O as StringField, P as literal, R as string, S as SchemaJSONSchema, T as SchemaResult, _ as ObjectField, a as FieldAtFieldPath, b as SchemaInput, c as FieldPath, d as FieldValue, f as InferInput, g as NumberField, h as LiteralField, i as DeepPartial, j as boolean, k as ValueAtFieldPath, l as FieldSchema, m as JSONValue, n as BleamSchema, o as FieldInput, p as InferOutput, r as BooleanField, s as FieldOutput, t as ArrayField, u as FieldToken, v as PrimitiveValue, w as SchemaPatch, x as SchemaIssue, y as SchemaError } from "./schema-LxnzAfgw.js";
1
+ import { A as array, C as SchemaOutput, D as StandardSchema, E as SchemaShape, F as number, I as object, L as schema, M as getFieldSchema, N as getValueAtPath, O as StringField, P as literal, R as string, S as SchemaJSONSchema, T as SchemaResult, _ as ObjectField, a as FieldAtFieldPath, b as SchemaInput, c as FieldPath, d as FieldValue, f as InferInput, g as NumberField, h as LiteralField, i as DeepPartial, j as boolean, k as ValueAtFieldPath, l as FieldSchema, m as JSONValue, n as BleamSchema, o as FieldInput, p as InferOutput, r as BooleanField, s as FieldOutput, t as ArrayField, u as FieldToken, v as PrimitiveValue, w as SchemaPatch, x as SchemaIssue, y as SchemaError } from "./schema-DsXZBnvc.js";
2
2
  export { ArrayField, BleamSchema, BooleanField, DeepPartial, FieldAtFieldPath, FieldInput, FieldOutput, FieldPath, FieldSchema, FieldToken, FieldValue, InferInput, InferOutput, JSONValue, LiteralField, NumberField, ObjectField, PrimitiveValue, SchemaError, SchemaInput, SchemaIssue, SchemaJSONSchema, SchemaOutput, SchemaPatch, SchemaResult, SchemaShape, StandardSchema, StringField, ValueAtFieldPath, array, boolean, getFieldSchema, getValueAtPath, literal, number, object, schema, string };
@@ -8,6 +8,8 @@ let jotai_vanilla = require("jotai/vanilla");
8
8
  jotai_vanilla = require_chunk.__toESM(jotai_vanilla);
9
9
  let jotai_family = require("jotai-family");
10
10
  jotai_family = require_chunk.__toESM(jotai_family);
11
+ let expo_sqlite = require("expo-sqlite");
12
+ expo_sqlite = require_chunk.__toESM(expo_sqlite);
11
13
 
12
14
  //#region src/state/atom.ts
13
15
  const storedAtomsKey = Symbol.for("bleam.state.storedAtoms.v1");
@@ -128,6 +130,55 @@ function internalJotaiWritableAtom(value) {
128
130
  }
129
131
  const internalStore = (0, jotai_vanilla.getDefaultStore)();
130
132
 
133
+ //#endregion
134
+ //#region src/native-sqlite.ts
135
+ const databases = /* @__PURE__ */ new Map();
136
+ function toExpoParameters(parameters) {
137
+ return parameters;
138
+ }
139
+ function toSQLiteValue(value) {
140
+ if (typeof value === "string" || typeof value === "number" || value === null) return value;
141
+ throw new Error("SQLite blobs are not supported by Bleam state yet");
142
+ }
143
+ function toSQLiteRow(row) {
144
+ const output = {};
145
+ for (const [key, value] of Object.entries(row)) output[key] = toSQLiteValue(value);
146
+ return output;
147
+ }
148
+ var NativeSQLiteDatabase = class NativeSQLiteDatabase {
149
+ constructor(database) {
150
+ this.database = database;
151
+ }
152
+ async execute(query, parameters) {
153
+ await this.database.runAsync(query, toExpoParameters(parameters) ?? []);
154
+ }
155
+ async select(query, parameters) {
156
+ return (await this.database.getAllAsync(query, toExpoParameters(parameters) ?? [])).map(toSQLiteRow);
157
+ }
158
+ async get(query, parameters) {
159
+ const row = await this.database.getFirstAsync(query, toExpoParameters(parameters) ?? []);
160
+ return row ? toSQLiteRow(row) : void 0;
161
+ }
162
+ async transaction(action) {
163
+ let result;
164
+ await this.database.withExclusiveTransactionAsync(async (transaction) => {
165
+ result = await action(new NativeSQLiteDatabase(transaction));
166
+ });
167
+ return result;
168
+ }
169
+ close() {
170
+ return this.database.closeAsync();
171
+ }
172
+ };
173
+ function openNativeSQLiteDatabase(name = "bleam.sqlite3") {
174
+ let database = databases.get(name);
175
+ if (!database) {
176
+ database = (0, expo_sqlite.openDatabaseAsync)(name).then((value) => new NativeSQLiteDatabase(value));
177
+ databases.set(name, database);
178
+ }
179
+ return database;
180
+ }
181
+
131
182
  //#endregion
132
183
  //#region src/state/collection.ts
133
184
  var CollectionVersionConflictError = class extends Error {
@@ -155,18 +206,18 @@ let jsonSqlSupportPromise;
155
206
  let mutationPipeline = Promise.resolve();
156
207
  let transactionCallbackStarting = false;
157
208
  function getDatabase() {
158
- databasePromise ??= Promise.resolve().then(() => require("./native-sqlite-Dw--FI9a.cjs")).then((module$1) => module$1.openNativeSQLiteDatabase(`${require_app_storage.currentAppStorageKey()}.sqlite3`));
209
+ databasePromise ??= Promise.resolve().then(() => openNativeSQLiteDatabase(`${require_app_storage.currentAppStorageKey()}.sqlite3`));
159
210
  return databasePromise;
160
211
  }
161
212
  async function initializedDatabase() {
162
213
  initializedPromise ??= (async () => {
163
214
  const database = await getDatabase();
164
215
  await database.execute("PRAGMA journal_mode = WAL");
165
- if (numberValue(await database.get("PRAGMA user_version"), "user_version", 0) !== schemaVersion) await database.transaction(async () => {
166
- await database.execute("DROP TABLE IF EXISTS links");
167
- await database.execute("DROP TABLE IF EXISTS collections");
168
- await createTables(database);
169
- await database.execute(`PRAGMA user_version = ${schemaVersion}`);
216
+ if (numberValue(await database.get("PRAGMA user_version"), "user_version", 0) !== schemaVersion) await database.transaction(async (transaction) => {
217
+ await transaction.execute("DROP TABLE IF EXISTS links");
218
+ await transaction.execute("DROP TABLE IF EXISTS collections");
219
+ await createTables(transaction);
220
+ await transaction.execute(`PRAGMA user_version = ${schemaVersion}`);
170
221
  });
171
222
  else await createTables(database);
172
223
  return database;
@@ -648,7 +699,7 @@ function enqueueMutation(action) {
648
699
  const database = await initializedDatabase();
649
700
  const changes = /* @__PURE__ */ new Map();
650
701
  try {
651
- const value = await database.transaction(() => action(database, changes));
702
+ const value = await database.transaction((transaction) => action(transaction, changes));
652
703
  publishChanges(changes);
653
704
  resolve(value);
654
705
  } catch (error) {
@@ -4,6 +4,7 @@ import { l as schema } from "./schema-B7ELMpuI.js";
4
4
  import { useAtom, useAtomValue, useSetAtom } from "jotai/react";
5
5
  import { atom, getDefaultStore } from "jotai/vanilla";
6
6
  import { atomFamily } from "jotai-family";
7
+ import { openDatabaseAsync } from "expo-sqlite";
7
8
 
8
9
  //#region src/state/atom.ts
9
10
  const storedAtomsKey = Symbol.for("bleam.state.storedAtoms.v1");
@@ -124,6 +125,55 @@ function internalJotaiWritableAtom(value) {
124
125
  }
125
126
  const internalStore = getDefaultStore();
126
127
 
128
+ //#endregion
129
+ //#region src/native-sqlite.ts
130
+ const databases = /* @__PURE__ */ new Map();
131
+ function toExpoParameters(parameters) {
132
+ return parameters;
133
+ }
134
+ function toSQLiteValue(value) {
135
+ if (typeof value === "string" || typeof value === "number" || value === null) return value;
136
+ throw new Error("SQLite blobs are not supported by Bleam state yet");
137
+ }
138
+ function toSQLiteRow(row) {
139
+ const output = {};
140
+ for (const [key, value] of Object.entries(row)) output[key] = toSQLiteValue(value);
141
+ return output;
142
+ }
143
+ var NativeSQLiteDatabase = class NativeSQLiteDatabase {
144
+ constructor(database) {
145
+ this.database = database;
146
+ }
147
+ async execute(query, parameters) {
148
+ await this.database.runAsync(query, toExpoParameters(parameters) ?? []);
149
+ }
150
+ async select(query, parameters) {
151
+ return (await this.database.getAllAsync(query, toExpoParameters(parameters) ?? [])).map(toSQLiteRow);
152
+ }
153
+ async get(query, parameters) {
154
+ const row = await this.database.getFirstAsync(query, toExpoParameters(parameters) ?? []);
155
+ return row ? toSQLiteRow(row) : void 0;
156
+ }
157
+ async transaction(action) {
158
+ let result;
159
+ await this.database.withExclusiveTransactionAsync(async (transaction) => {
160
+ result = await action(new NativeSQLiteDatabase(transaction));
161
+ });
162
+ return result;
163
+ }
164
+ close() {
165
+ return this.database.closeAsync();
166
+ }
167
+ };
168
+ function openNativeSQLiteDatabase(name = "bleam.sqlite3") {
169
+ let database = databases.get(name);
170
+ if (!database) {
171
+ database = openDatabaseAsync(name).then((value) => new NativeSQLiteDatabase(value));
172
+ databases.set(name, database);
173
+ }
174
+ return database;
175
+ }
176
+
127
177
  //#endregion
128
178
  //#region src/state/collection.ts
129
179
  var CollectionVersionConflictError = class extends Error {
@@ -151,18 +201,18 @@ let jsonSqlSupportPromise;
151
201
  let mutationPipeline = Promise.resolve();
152
202
  let transactionCallbackStarting = false;
153
203
  function getDatabase() {
154
- databasePromise ??= import("./native-sqlite-WzRNzCSh.js").then((module) => module.openNativeSQLiteDatabase(`${currentAppStorageKey()}.sqlite3`));
204
+ databasePromise ??= Promise.resolve().then(() => openNativeSQLiteDatabase(`${currentAppStorageKey()}.sqlite3`));
155
205
  return databasePromise;
156
206
  }
157
207
  async function initializedDatabase() {
158
208
  initializedPromise ??= (async () => {
159
209
  const database = await getDatabase();
160
210
  await database.execute("PRAGMA journal_mode = WAL");
161
- if (numberValue(await database.get("PRAGMA user_version"), "user_version", 0) !== schemaVersion) await database.transaction(async () => {
162
- await database.execute("DROP TABLE IF EXISTS links");
163
- await database.execute("DROP TABLE IF EXISTS collections");
164
- await createTables(database);
165
- await database.execute(`PRAGMA user_version = ${schemaVersion}`);
211
+ if (numberValue(await database.get("PRAGMA user_version"), "user_version", 0) !== schemaVersion) await database.transaction(async (transaction) => {
212
+ await transaction.execute("DROP TABLE IF EXISTS links");
213
+ await transaction.execute("DROP TABLE IF EXISTS collections");
214
+ await createTables(transaction);
215
+ await transaction.execute(`PRAGMA user_version = ${schemaVersion}`);
166
216
  });
167
217
  else await createTables(database);
168
218
  return database;
@@ -644,7 +694,7 @@ function enqueueMutation(action) {
644
694
  const database = await initializedDatabase();
645
695
  const changes = /* @__PURE__ */ new Map();
646
696
  try {
647
- const value = await database.transaction(() => action(database, changes));
697
+ const value = await database.transaction((transaction) => action(transaction, changes));
648
698
  publishChanges(changes);
649
699
  resolve(value);
650
700
  } catch (error) {
package/dist/state.cjs CHANGED
@@ -2,7 +2,7 @@ require('./native-runtime-CsXnXkQn.cjs');
2
2
  require('./crypto-CT3VZ7lF.cjs');
3
3
  require('./app-storage-D8W4n8ey.cjs');
4
4
  const require_schema = require('./schema-B7SLUBLN.cjs');
5
- const require_state = require('./state-BZYyrE2-.cjs');
5
+ const require_state = require('./state-Bm9GiRnU.cjs');
6
6
 
7
7
  exports.CollectionVersionConflictError = require_state.CollectionVersionConflictError;
8
8
  exports.array = require_schema.array;
package/dist/state.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as array, C as SchemaOutput, E as SchemaShape, F as number, I as object, P as literal, R as string, _ as ObjectField, b as SchemaInput, c as FieldPath, j as boolean, k as ValueAtFieldPath, s as FieldOutput, w as SchemaPatch } from "./schema-LxnzAfgw.js";
1
+ import { A as array, C as SchemaOutput, E as SchemaShape, F as number, I as object, P as literal, R as string, _ as ObjectField, b as SchemaInput, c as FieldPath, j as boolean, k as ValueAtFieldPath, s as FieldOutput, w as SchemaPatch } from "./schema-DsXZBnvc.js";
2
2
  import "jotai/vanilla";
3
3
 
4
4
  //#region src/state/atom.d.ts
package/dist/state.js CHANGED
@@ -2,6 +2,6 @@ import "./native-runtime-C85Nuc4F.js";
2
2
  import "./crypto-BB92-Upx.js";
3
3
  import "./app-storage-Isi5Bo0R.js";
4
4
  import { c as object, n as array, o as literal, r as boolean, s as number, u as string } from "./schema-B7ELMpuI.js";
5
- import { a as transactionAtom, c as useRow, h as useSetAtom, i as queryAtom, l as atom, m as useAtomValue, n as atomCollection, o as useField, p as useAtom, r as mutateAtom, s as useList, t as CollectionVersionConflictError } from "./state-DkaRFkZJ.js";
5
+ import { a as transactionAtom, c as useRow, h as useSetAtom, i as queryAtom, l as atom, m as useAtomValue, n as atomCollection, o as useField, p as useAtom, r as mutateAtom, s as useList, t as CollectionVersionConflictError } from "./state-D8Firo9w.js";
6
6
 
7
7
  export { CollectionVersionConflictError, array, atom, atomCollection, boolean, literal, mutateAtom, number, object, queryAtom, string, transactionAtom, useAtom, useAtomValue, useField, useList, useRow, useSetAtom };
package/dist/window.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as SymbolName } from "./elements-CFk0QHw0.cjs";
1
+ import { n as SymbolName } from "./elements-gEI8YGl1.cjs";
2
2
  import * as react3 from "react";
3
3
  import { ComponentType } from "react";
4
4
  import { StyleProp, ViewStyle } from "react-native";
package/dist/window.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { n as SymbolName } from "./elements-ClGQ41Sc.js";
2
- import * as react5 from "react";
1
+ import { n as SymbolName } from "./elements-DX_YUveu.js";
2
+ import * as react3 from "react";
3
3
  import { ComponentType } from "react";
4
4
  import { StyleProp, ViewStyle } from "react-native";
5
5
 
@@ -55,7 +55,7 @@ type SidebarNavigatorConfig<Routes extends SidebarScreenMap> = {
55
55
  style?: StyleProp<ViewStyle>;
56
56
  };
57
57
  declare function createSidebarNavigator<const Routes extends SidebarScreenMap>(config: SidebarNavigatorConfig<Routes>): {
58
- Navigator: () => react5.JSX.Element;
58
+ Navigator: () => react3.JSX.Element;
59
59
  useNavigation: () => SidebarNavigation<Routes>;
60
60
  useRoute: () => SidebarRouteState<Routes>;
61
61
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bleam",
3
- "version": "0.0.13",
4
- "packageManager": "yarn@1.22.22",
3
+ "version": "0.0.14",
4
+ "packageManager": "yarn@4.17.1",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -10,9 +10,7 @@
10
10
  "tsconfig.json",
11
11
  "tsconfig.base.json"
12
12
  ],
13
- "bin": {
14
- "bleam": "dist/cli.js"
15
- },
13
+ "bin": "dist/cli.js",
16
14
  "scripts": {
17
15
  "build": "tsdown",
18
16
  "prepublishOnly": "tsdown",
@@ -30,11 +28,11 @@
30
28
  "dependencies": {
31
29
  "@biomejs/biome": "^2.2.0",
32
30
  "@expo/metro": "56.0.0",
33
- "@nativescript-community/sqlite": "^3.5.9",
34
31
  "@nativescript/react-native": "9.0.0-preview.4",
35
32
  "@types/react": "~19.2.17",
36
33
  "expo": "57",
37
34
  "expo-splash-screen": "57.0.2",
35
+ "expo-sqlite": "~57.0.1",
38
36
  "jotai": "2.20.2",
39
37
  "jotai-family": "1.0.2",
40
38
  "react": "19.2.3",
@@ -1,139 +1,17 @@
1
- import { Button } from 'bleam/elements'
2
- import { atom, useAtom } from 'bleam/state'
3
1
  import { sx } from 'bleam/styles'
4
- import { Toolbar, Window } from 'bleam/window'
2
+ import { Window } from 'bleam/window'
5
3
  import { Text, View } from 'react-native'
6
4
 
7
5
  const appName = 'Bleam Basic'
8
- const counter = atom(0)
9
6
 
10
7
  export default function App() {
11
- const [count, setCount] = useAtom(counter)
12
-
13
8
  return (
14
- <View style={sx('flex-1')}>
15
- <Window title={appName} titleVisibility="visible" />
16
- <Toolbar toolbarStyle="unified" />
17
-
18
- <View style={sx('flex-1', 'items-center', 'justify-center', 'p-6')}>
19
- <View style={sx('flex-1', 'w-full', 'max-w-5xl', 'max-h-3xl')}>
20
- <View style={sx('flex-1', 'items-center', 'justify-center', 'px-6')}>
21
- <View style={sx('items-center', 'gap-8')}>
22
- <View
23
- style={sx('h-44', 'w-44', 'items-center', 'justify-center')}
24
- >
25
- <View
26
- style={sx(
27
- 'absolute',
28
- 'top-0',
29
- 'h-24',
30
- 'w-32',
31
- 'rounded-2xl',
32
- 'border',
33
- 'border-tertiary-label',
34
- 'bg-system',
35
- 'items-center',
36
- 'justify-center',
37
- 'rotate-30',
38
- )}
39
- >
40
- <Text
41
- style={sx(
42
- 'text-3xl',
43
- 'font-semibold',
44
- 'text-system-cyan',
45
- '-rotate-30',
46
- )}
47
- >
48
- B
49
- </Text>
50
- </View>
51
-
52
- <View
53
- style={sx(
54
- 'absolute',
55
- 'bottom-2',
56
- 'h-24',
57
- 'w-32',
58
- 'rounded-2xl',
59
- 'border-2',
60
- 'border-system-purple',
61
- 'bg-secondary-system',
62
- 'items-center',
63
- 'justify-center',
64
- 'rotate-30',
65
- )}
66
- >
67
- <Text
68
- style={sx(
69
- 'text-3xl',
70
- 'font-bold',
71
- 'text-system-purple',
72
- '-rotate-30',
73
- )}
74
- >
75
- JS
76
- </Text>
77
- </View>
78
- </View>
79
-
80
- <View style={sx('items-center')}>
81
- <Text
82
- style={sx(
83
- 'text-5xl',
84
- 'font-semibold',
85
- 'tracking-tighter',
86
- 'text-label',
87
- 'text-center',
88
- )}
89
- >
90
- Get started
91
- </Text>
92
- <Text
93
- style={sx(
94
- 'mt-6',
95
- 'text-lg',
96
- 'text-secondary-label',
97
- 'text-center',
98
- )}
99
- >
100
- Edit{' '}
101
- <Text
102
- style={sx(
103
- 'rounded-md',
104
- 'italic',
105
- 'px-2',
106
- 'py-1',
107
- 'text-label',
108
- )}
109
- >
110
- app/index.tsx
111
- </Text>{' '}
112
- and save to test{' '}
113
- <Text
114
- style={sx(
115
- 'rounded-md',
116
- 'italic',
117
- 'px-2',
118
- 'py-1',
119
- 'text-label',
120
- )}
121
- >
122
- live reload
123
- </Text>
124
- </Text>
125
- </View>
126
-
127
- <Button
128
- label={`Count is ${count}`}
129
- variant="secondary"
130
- size="regular"
131
- onPress={() => setCount((value) => value + 1)}
132
- />
133
- </View>
134
- </View>
135
- </View>
136
- </View>
9
+ <View style={sx('flex-1', 'items-center', 'justify-center', 'px-6')}>
10
+ <Window title={appName} />
11
+ <Text style={sx('text-3xl', 'font-bold', 'text-label')}>{appName}</Text>
12
+ <Text style={sx('mt-2', 'text-base', 'text-secondary-label')}>
13
+ Open app/index.tsx to start working on your app.
14
+ </Text>
137
15
  </View>
138
16
  )
139
17
  }
@@ -1,13 +1,47 @@
1
1
  import { chat, useChat, useChatList } from 'bleam/ai'
2
- import { Button } from 'bleam/elements'
2
+ import {
3
+ Button,
4
+ Conversation,
5
+ ConversationContent,
6
+ ConversationEmptyState,
7
+ ConversationScrollButton,
8
+ Message,
9
+ MessageActions,
10
+ MessageContent,
11
+ MessageStatus,
12
+ MessageText,
13
+ PromptInput,
14
+ PromptInputFooter,
15
+ PromptInputSubmit,
16
+ PromptInputTextarea,
17
+ } from 'bleam/elements'
3
18
  import { sx } from 'bleam/styles'
4
19
  import { Window } from 'bleam/window'
5
- import { useEffect, useRef, useState } from 'react'
6
- import { Text, TextInput, View } from 'react-native'
20
+ import { Suspense, useEffect, useRef, useState } from 'react'
21
+ import { Text, View } from 'react-native'
7
22
 
8
23
  const appName = 'Bleam Basic'
9
24
 
10
25
  export default function App() {
26
+ return (
27
+ <View style={sx('flex-1', 'p-8', 'gap-6')}>
28
+ <Window title={appName} />
29
+ <Text style={sx('text-3xl', 'font-semibold')}>Foundation Models</Text>
30
+ <Text style={sx('text-secondary-label')}>
31
+ Chats persist on this Mac and use Apple Foundation Models by default.
32
+ </Text>
33
+ <Suspense
34
+ fallback={
35
+ <Text style={sx('text-secondary-label')}>Loading local chats...</Text>
36
+ }
37
+ >
38
+ <ChatSession />
39
+ </Suspense>
40
+ </View>
41
+ )
42
+ }
43
+
44
+ function ChatSession() {
11
45
  const chats = useChatList()
12
46
  const creating = useRef(false)
13
47
  const [error, setError] = useState('')
@@ -25,15 +59,10 @@ export default function App() {
25
59
  }, [chats.length])
26
60
 
27
61
  return (
28
- <View style={sx('flex-1', 'p-8', 'gap-6')}>
29
- <Window title={appName} />
30
- <Text style={sx('text-3xl', 'font-semibold')}>Foundation Models</Text>
31
- <Text style={sx('text-secondary-label')}>
32
- Chats persist on this Mac and use Apple Foundation Models by default.
33
- </Text>
62
+ <View style={sx('flex-1')}>
34
63
  {error ? <Text style={sx('text-system-red')}>{error}</Text> : null}
35
64
  {chats[0] ? (
36
- <Conversation id={chats[0].id} />
65
+ <ChatConversation id={chats[0].id} />
37
66
  ) : (
38
67
  <Text>Creating chat...</Text>
39
68
  )}
@@ -41,7 +70,7 @@ export default function App() {
41
70
  )
42
71
  }
43
72
 
44
- function Conversation({ id }: { id: string }) {
73
+ function ChatConversation({ id }: { id: string }) {
45
74
  const conversation = useChat(id, {
46
75
  system: 'You suggest practical, concise native Mac app ideas.',
47
76
  })
@@ -56,39 +85,69 @@ function Conversation({ id }: { id: string }) {
56
85
  : null
57
86
 
58
87
  return (
59
- <View style={sx('gap-4')}>
60
- <TextInput
88
+ <View style={sx('flex-1', 'gap-4')}>
89
+ <Conversation>
90
+ <ConversationContent
91
+ data={conversation.messages}
92
+ keyExtractor={(message) => message.id}
93
+ ListEmptyComponent={
94
+ <ConversationEmptyState
95
+ title="Start a conversation"
96
+ description="Ask for a practical native Mac app idea."
97
+ />
98
+ }
99
+ renderItem={({ item: message }) => (
100
+ <Message from={message.role}>
101
+ {message.content ? (
102
+ <MessageContent>
103
+ <MessageText>{message.content}</MessageText>
104
+ </MessageContent>
105
+ ) : null}
106
+ {message.status !== 'completed' ? (
107
+ <MessageStatus status={message.status} />
108
+ ) : null}
109
+ {retryable?.id === message.id ? (
110
+ <MessageActions>
111
+ <Button
112
+ label="Retry"
113
+ size="small"
114
+ variant="secondary"
115
+ onPress={() => void conversation.retry(message.id)}
116
+ />
117
+ </MessageActions>
118
+ ) : null}
119
+ </Message>
120
+ )}
121
+ />
122
+ <ConversationScrollButton />
123
+ </Conversation>
124
+
125
+ <PromptInput
126
+ disabled={!conversation.canSend && !conversation.canCancel}
127
+ status={conversation.status}
61
128
  value={prompt}
62
129
  onChangeText={setPrompt}
63
- style={sx('rounded-xl', 'border', 'border-separator', 'p-4')}
64
- />
65
- <View style={sx('flex-row', 'gap-3')}>
66
- <Button
67
- label="Send"
68
- loading={conversation.isGenerating}
69
- disabled={!conversation.canSend}
70
- onPress={() => void conversation.send(prompt)}
71
- />
72
- <Button
73
- label="Cancel"
74
- variant="secondary"
75
- disabled={!conversation.canCancel}
76
- onPress={() => void conversation.cancel()}
77
- />
78
- {retryable ? (
79
- <Button
80
- label="Retry"
81
- variant="secondary"
82
- onPress={() => void conversation.retry(retryable.id)}
130
+ onSubmit={({ text }) => {
131
+ setPrompt('')
132
+ void conversation.send(text)
133
+ }}
134
+ >
135
+ <PromptInputTextarea />
136
+ <PromptInputFooter>
137
+ <View />
138
+ <PromptInputSubmit
139
+ disabled={!conversation.canCancel && !prompt.trim()}
140
+ onPress={({ text }) => {
141
+ if (conversation.canCancel) {
142
+ void conversation.cancel()
143
+ } else {
144
+ setPrompt('')
145
+ void conversation.send(text)
146
+ }
147
+ }}
83
148
  />
84
- ) : null}
85
- </View>
86
- {conversation.messages.map((message) => (
87
- <Text key={message.id} style={sx('text-lg', 'text-label')}>
88
- {message.role === 'user' ? 'You: ' : 'Assistant: '}
89
- {message.content || message.status}
90
- </Text>
91
- ))}
149
+ </PromptInputFooter>
150
+ </PromptInput>
92
151
  </View>
93
152
  )
94
153
  }
@@ -71,6 +71,8 @@ PODS:
71
71
  - ExpoModulesWorklets (57.0.2):
72
72
  - ExpoModulesCore
73
73
  - ExpoModulesJSI
74
+ - ExpoSQLite (57.0.1):
75
+ - ExpoModulesCore
74
76
  - FBLazyVector (0.86.0)
75
77
  - hermes-engine (250829098.0.14):
76
78
  - hermes-engine/Pre-built (= 250829098.0.14)
@@ -1932,6 +1934,7 @@ DEPENDENCIES:
1932
1934
  - ExpoModulesCore (from `../node_modules/expo-modules-core`)
1933
1935
  - ExpoModulesJSI (from `../node_modules/expo-modules-jsi/apple`)
1934
1936
  - ExpoModulesWorklets (from `../node_modules/expo-modules-core`)
1937
+ - ExpoSQLite (from `../node_modules/expo-sqlite/ios`)
1935
1938
  - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
1936
1939
  - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
1937
1940
  - "NativeScriptNativeApi (from `../node_modules/@nativescript/react-native`)"
@@ -2035,6 +2038,8 @@ EXTERNAL SOURCES:
2035
2038
  :path: "../node_modules/expo-modules-jsi/apple"
2036
2039
  ExpoModulesWorklets:
2037
2040
  :path: "../node_modules/expo-modules-core"
2041
+ ExpoSQLite:
2042
+ :path: "../node_modules/expo-sqlite/ios"
2038
2043
  FBLazyVector:
2039
2044
  :path: "../node_modules/react-native/Libraries/FBLazyVector"
2040
2045
  hermes-engine:
@@ -2202,6 +2207,7 @@ SPEC CHECKSUMS:
2202
2207
  ExpoModulesCore: 747a01dfe7af61ad2e869f80bf983af1caa63378
2203
2208
  ExpoModulesJSI: ef7f197a8e7eeb245557f560ade794bfc1abdc79
2204
2209
  ExpoModulesWorklets: 0340ed9a30017f8597b90a1ef9aa210c43e44c4b
2210
+ ExpoSQLite: ddd65ed74bdebcff20f6766e682f9321ecb28ab8
2205
2211
  FBLazyVector: b3e7ad108f0d882e30445c5527d774e3fd432f3d
2206
2212
  hermes-engine: 6f298675a7f5d45e1a61a3c664a2b9618befb1e1
2207
2213
  NativeScriptNativeApi: b35cf5bb2727adf20eb13d2b1bd8651d0698a362