@objectstack/client-react 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +158 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @objectstack/client-react
|
|
2
2
|
|
|
3
|
+
## 0.9.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @objectstack/spec@0.9.2
|
|
9
|
+
- @objectstack/client@0.9.2
|
|
10
|
+
- @objectstack/core@0.9.2
|
|
11
|
+
|
|
12
|
+
## 0.9.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Patch release for maintenance and stability improvements. All packages updated with unified versioning.
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @objectstack/spec@0.9.1
|
|
19
|
+
- @objectstack/core@0.9.1
|
|
20
|
+
- @objectstack/client@0.9.1
|
|
21
|
+
|
|
3
22
|
## 0.8.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
React hooks for ObjectStack Client SDK - Type-safe data fetching and mutations for React applications.
|
|
4
4
|
|
|
5
|
+
## 🤖 AI Development Context
|
|
6
|
+
|
|
7
|
+
**Role**: React Bindings for Client SDK
|
|
8
|
+
**Usage**:
|
|
9
|
+
- Use `useQuery`, `useMutation` hooks.
|
|
10
|
+
- Similar to TanStack Query but specialized for ObjectStack.
|
|
11
|
+
|
|
5
12
|
## Installation
|
|
6
13
|
|
|
7
14
|
```bash
|
|
@@ -268,6 +275,157 @@ const { mutate } = useMutation<Task, Partial<Task>>('todo_task', 'create');
|
|
|
268
275
|
// mutate expects Partial<Task>
|
|
269
276
|
```
|
|
270
277
|
|
|
278
|
+
## Common Patterns
|
|
279
|
+
|
|
280
|
+
### Master-Detail View
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
function TaskList() {
|
|
284
|
+
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
285
|
+
|
|
286
|
+
const { data: tasks } = useQuery('todo_task', {
|
|
287
|
+
select: ['id', 'subject'],
|
|
288
|
+
sort: ['-created_at']
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const { data: selectedTask } = useQuery('todo_task', {
|
|
292
|
+
filters: ['id', '=', selectedId],
|
|
293
|
+
enabled: !!selectedId // Only fetch when ID is selected
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<div className="flex">
|
|
298
|
+
<TaskListPanel tasks={tasks?.value} onSelect={setSelectedId} />
|
|
299
|
+
<TaskDetail task={selectedTask?.value?.[0]} />
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Optimistic Updates
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
function TaskToggle({ taskId, completed }) {
|
|
309
|
+
const { mutate } = useMutation('todo_task', 'update', {
|
|
310
|
+
onMutate: async (variables) => {
|
|
311
|
+
// Optimistically update UI
|
|
312
|
+
return { previousValue: completed };
|
|
313
|
+
},
|
|
314
|
+
onError: (error, variables, context) => {
|
|
315
|
+
// Revert on error
|
|
316
|
+
console.error('Update failed, reverting', context.previousValue);
|
|
317
|
+
},
|
|
318
|
+
onSuccess: () => {
|
|
319
|
+
// Refetch to ensure data consistency
|
|
320
|
+
queryClient.invalidateQueries(['todo_task']);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
return (
|
|
325
|
+
<Checkbox
|
|
326
|
+
checked={completed}
|
|
327
|
+
onChange={(e) => mutate({ id: taskId, is_completed: e.target.checked })}
|
|
328
|
+
/>
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Dependent Queries
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
function ProjectTasks({ projectId }) {
|
|
337
|
+
// First, get project details
|
|
338
|
+
const { data: project } = useQuery('project', {
|
|
339
|
+
filters: ['id', '=', projectId]
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Then, get tasks for this project
|
|
343
|
+
const { data: tasks } = useQuery('todo_task', {
|
|
344
|
+
filters: ['project_id', '=', projectId],
|
|
345
|
+
enabled: !!project // Only fetch when project is loaded
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<div>
|
|
350
|
+
<h2>{project?.value?.[0]?.name}</h2>
|
|
351
|
+
<TaskList tasks={tasks?.value} />
|
|
352
|
+
</div>
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Search with Debounce
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
import { useDeferredValue } from 'react';
|
|
361
|
+
|
|
362
|
+
function TaskSearch() {
|
|
363
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
364
|
+
const deferredSearch = useDeferredValue(searchTerm);
|
|
365
|
+
|
|
366
|
+
const { data, isLoading } = useQuery('todo_task', {
|
|
367
|
+
filters: ['subject', 'contains', deferredSearch],
|
|
368
|
+
enabled: deferredSearch.length >= 3 // Only search with 3+ chars
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<div>
|
|
373
|
+
<input
|
|
374
|
+
type="text"
|
|
375
|
+
value={searchTerm}
|
|
376
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
377
|
+
placeholder="Search tasks..."
|
|
378
|
+
/>
|
|
379
|
+
{isLoading && <Spinner />}
|
|
380
|
+
<TaskList tasks={data?.value} />
|
|
381
|
+
</div>
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Form with Validation
|
|
387
|
+
|
|
388
|
+
```tsx
|
|
389
|
+
function TaskForm() {
|
|
390
|
+
const { mutate, isLoading, error } = useMutation('todo_task', 'create', {
|
|
391
|
+
onSuccess: () => {
|
|
392
|
+
router.push('/tasks');
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
|
397
|
+
e.preventDefault();
|
|
398
|
+
const formData = new FormData(e.currentTarget);
|
|
399
|
+
|
|
400
|
+
mutate({
|
|
401
|
+
subject: formData.get('subject'),
|
|
402
|
+
priority: Number(formData.get('priority')),
|
|
403
|
+
due_date: formData.get('due_date')
|
|
404
|
+
});
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<form onSubmit={handleSubmit}>
|
|
409
|
+
<input name="subject" required />
|
|
410
|
+
<input name="priority" type="number" min="1" max="5" />
|
|
411
|
+
<input name="due_date" type="date" />
|
|
412
|
+
|
|
413
|
+
{error && (
|
|
414
|
+
<div className="error">
|
|
415
|
+
{error.code === 'validation_error'
|
|
416
|
+
? 'Please check your input'
|
|
417
|
+
: error.message}
|
|
418
|
+
</div>
|
|
419
|
+
)}
|
|
420
|
+
|
|
421
|
+
<button type="submit" disabled={isLoading}>
|
|
422
|
+
{isLoading ? 'Creating...' : 'Create Task'}
|
|
423
|
+
</button>
|
|
424
|
+
</form>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
271
429
|
## License
|
|
272
430
|
|
|
273
431
|
Apache-2.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/client-react",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "React hooks for ObjectStack Client SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"react": ">=18.0.0"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@objectstack/client": "0.9.
|
|
12
|
-
"@objectstack/spec": "0.9.
|
|
13
|
-
"@objectstack/core": "0.9.
|
|
11
|
+
"@objectstack/client": "0.9.2",
|
|
12
|
+
"@objectstack/spec": "0.9.2",
|
|
13
|
+
"@objectstack/core": "0.9.2"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/react": "^18.0.0",
|