Skip to content

Commit 2d2dd77

Browse files
authored
Prep for initial release (#2)
1 parent 6dadba4 commit 2d2dd77

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+9549
-5434
lines changed

.changeset/tasty-results-doubt.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@tanstack/react-optimistic": patch
3+
"@tanstack/optimistic": patch
4+
---
5+
6+
Initial release

README.md

+37-26
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const { data, insert, update, delete: deleteFn } = useCollection({
6767
```
6868

6969
Returns:
70+
7071
- `data`: An array of all items in the collection
7172
- `state`: A Map containing all items in the collection with their internal keys
7273
- `insert`: Function to add new items to the collection
@@ -87,6 +88,7 @@ await preloadCollection({
8788
```
8889

8990
Features:
91+
9092
1. Returns a promise that resolves when the first sync commit is complete
9193
2. Shares the same collection instance with `useCollection`
9294
3. Handles already-loaded collections by returning immediately
@@ -98,16 +100,16 @@ Features:
98100

99101
```typescript
100102
// Insert a single item
101-
insert({ text: "Buy groceries", completed: false });
103+
insert({ text: "Buy groceries", completed: false })
102104

103105
// Insert multiple items
104106
insert([
105107
{ text: "Buy groceries", completed: false },
106-
{ text: "Walk dog", completed: false }
107-
]);
108+
{ text: "Walk dog", completed: false },
109+
])
108110

109111
// Insert with custom key
110-
insert({ text: "Buy groceries" }, { key: "grocery-task" });
112+
insert({ text: "Buy groceries" }, { key: "grocery-task" })
111113
```
112114

113115
#### Update
@@ -116,30 +118,34 @@ We use a proxy to capture updates as immutable draft optimistic updates.
116118

117119
```typescript
118120
// Update a single item
119-
update(todo, (draft) => { draft.completed = true });
121+
update(todo, (draft) => {
122+
draft.completed = true
123+
})
120124

121125
// Update multiple items
122126
update([todo1, todo2], (drafts) => {
123-
drafts.forEach(draft => { draft.completed = true });
124-
});
127+
drafts.forEach((draft) => {
128+
draft.completed = true
129+
})
130+
})
125131

126132
// Update with metadata
127-
update(todo, { metadata: { reason: "user update" } }, (draft) => {
128-
draft.text = "Updated text";
129-
});
133+
update(todo, { metadata: { reason: "user update" } }, (draft) => {
134+
draft.text = "Updated text"
135+
})
130136
```
131137

132138
#### Delete
133139

134140
```typescript
135141
// Delete a single item
136-
delete(todo);
142+
delete todo
137143

138144
// Delete multiple items
139-
delete([todo1, todo2]);
145+
delete [todo1, todo2]
140146

141147
// Delete with metadata
142-
delete(todo, { metadata: { reason: "completed" } });
148+
delete (todo, { metadata: { reason: "completed" } })
143149
```
144150

145151
### Schema Validation
@@ -148,11 +154,15 @@ Collections can optionally include a [standard schema](https://github.com/standa
148154

149155
```typescript
150156
const todoCollection = useCollection({
151-
id: 'todos',
152-
sync: { /* sync config */ },
153-
mutationFn: { /* mutation functions */ },
154-
schema: todoSchema // Standard schema interface
155-
});
157+
id: "todos",
158+
sync: {
159+
/* sync config */
160+
},
161+
mutationFn: {
162+
/* mutation functions */
163+
},
164+
schema: todoSchema, // Standard schema interface
165+
})
156166
```
157167

158168
## Transaction Management
@@ -163,6 +173,7 @@ The library includes a robust transaction management system:
163173
- `TransactionStore`: Provides persistent storage for transactions using IndexedDB
164174

165175
Transactions progress through several states:
176+
166177
1. `pending`: Initial state when a transaction is created
167178
2. `persisting`: Transaction is being persisted to the backend
168179
3. `completed`: Transaction has been successfully persisted
@@ -241,31 +252,31 @@ export async function loader() {
241252
// Example usage in a component
242253
function TodoList() {
243254
const { data, insert, update, delete: remove } = useCollection(todosConfig);
244-
255+
245256
const addTodo = () => {
246257
insert({ title: 'New todo', completed: false });
247258
};
248-
259+
249260
const toggleTodo = (todo) => {
250261
update(todo, (draft) => {
251262
draft.completed = !draft.completed;
252263
});
253264
};
254-
265+
255266
const removeTodo = (todo) => {
256267
remove(todo);
257268
};
258-
269+
259270
return (
260271
<div>
261272
<button onClick={addTodo}>Add Todo</button>
262273
<ul>
263274
{data.map(todo => (
264275
<li key={todo.id}>
265-
<input
266-
type="checkbox"
267-
checked={todo.completed}
268-
onChange={() => toggleTodo(todo)}
276+
<input
277+
type="checkbox"
278+
checked={todo.completed}
279+
onChange={() => toggleTodo(todo)}
269280
/>
270281
{todo.title}
271282
<button onClick={() => removeTodo(todo)}>Delete</button>

todo-app/README.md renamed to examples/react/todo/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
## How to run
44

55
- Install packages
6-
`pnpm install`
6+
`pnpm install`
77

88
- Start dev server & Docker containers
9-
`cd todo-app & pnpm dev`
9+
`pnpm dev`
1010

1111
- Run db migrations
12-
`cd todo-app & pnpm db:push`
12+
`pnpm db:push`

todo-app/docker-compose.yml renamed to examples/react/todo/docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '3.8'
1+
version: "3.8"
22
services:
33
postgres:
44
image: postgres:17-alpine
File renamed without changes.

todo-app/drizzle/meta/0000_snapshot.json renamed to examples/react/todo/drizzle/meta/0000_snapshot.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@
6262
"schemas": {},
6363
"tables": {}
6464
}
65-
}
65+
}

todo-app/drizzle/meta/0001_snapshot.json renamed to examples/react/todo/drizzle/meta/0001_snapshot.json

+2-4
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@
4848
"config_key_unique": {
4949
"name": "config_key_unique",
5050
"nullsNotDistinct": false,
51-
"columns": [
52-
"key"
53-
]
51+
"columns": ["key"]
5452
}
5553
},
5654
"policies": {},
@@ -115,4 +113,4 @@
115113
"schemas": {},
116114
"tables": {}
117115
}
118-
}
116+
}

todo-app/drizzle/meta/0002_snapshot.json renamed to examples/react/todo/drizzle/meta/0002_snapshot.json

+2-4
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@
4747
"uniqueConstraints": {
4848
"config_key_unique": {
4949
"name": "config_key_unique",
50-
"columns": [
51-
"key"
52-
],
50+
"columns": ["key"],
5351
"nullsNotDistinct": false
5452
}
5553
},
@@ -115,4 +113,4 @@
115113
"schemas": {},
116114
"tables": {}
117115
}
118-
}
116+
}

todo-app/drizzle/meta/_journal.json renamed to examples/react/todo/drizzle/meta/_journal.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
"breakpoints": true
2525
}
2626
]
27-
}
27+
}

todo-app/index.html renamed to examples/react/todo/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<link href="/src/styles.css" rel="stylesheet">
7+
<link href="/src/styles.css" rel="stylesheet" />
88
<title>TODO App</title>
99
</head>
1010
<body>

examples/react/todo/package.json

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"name": "todo-app",
3+
"private": true,
4+
"version": "0.0.0",
5+
"dependencies": {
6+
"@tanstack/react-optimistic": "workspace:*",
7+
"cors": "^2.8.5",
8+
"drizzle-orm": "^0.40.1",
9+
"drizzle-zod": "^0.7.0",
10+
"express": "^4.19.2",
11+
"postgres": "^3.4.5",
12+
"react": "^19.0.0",
13+
"react-dom": "^19.0.0",
14+
"tailwindcss": "^4.0.17",
15+
"zod": "^3.24.2"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.22.0",
19+
"@tailwindcss/vite": "^4.0.0-alpha.8",
20+
"@types/cors": "^2.8.17",
21+
"@types/express": "^4.17.21",
22+
"@types/node": "^22.13.10",
23+
"@types/pg": "^8.11.11",
24+
"@types/react": "^19.0.12",
25+
"@types/react-dom": "^19.0.0",
26+
"@typescript-eslint/eslint-plugin": "^8.26.1",
27+
"@typescript-eslint/parser": "^8.26.1",
28+
"@vitejs/plugin-react": "^4.3.4",
29+
"concurrently": "^9.1.2",
30+
"dotenv": "^16.3.1",
31+
"drizzle-kit": "^0.30.5",
32+
"eslint": "^9.22.0",
33+
"eslint-plugin-react-hooks": "^5.2.0",
34+
"eslint-plugin-react-refresh": "^0.4.5",
35+
"tsx": "^4.6.2",
36+
"typescript": "^5.8.2",
37+
"vite": "^6.2.2"
38+
},
39+
"private": true,
40+
"scripts": {
41+
"api:dev": "tsx watch src/api/server.ts",
42+
"build": "tsc -b && vite build",
43+
"db:ensure-config": "tsx scripts/ensure-default-config.ts",
44+
"db:generate": "drizzle-kit generate",
45+
"db:push": "tsx scripts/migrate.ts",
46+
"db:studio": "drizzle-kit studio",
47+
"dev": "docker-compose up -d && concurrently \"pnpm api:dev\" \"vite\"",
48+
"lint": "eslint .",
49+
"preview": "vite preview"
50+
},
51+
"type": "module"
52+
}

0 commit comments

Comments
 (0)