use-abcd 1.4.0 → 1.4.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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [![Build Status](https://github.com/smtrd3/common-state/workflows/CI/badge.svg)](https://github.com/smtrd3/common-state/actions)
4
4
 
5
+ Most apps are just CRUD operations in disguise. Stop fighting complex state management frameworks and reinventing patterns. This library gives you optimized CRUD state management with built-in sync and offline-first support. Get zero-latency updates, no loading screens, and effortless API integration. Your code stays simple, your users get instant responses.
6
+
5
7
  A powerful React hook for managing ABCD (or CRUD) operations with optimistic updates, caching, and automatic state management.
6
8
 
7
9
  > **Note on Package Name**: The package is published as `use-abcd` on npm due to naming availability, where ABCD stands for Add, Browse, Change, and Delete - which maps directly to the traditional CRUD (Create, Read, Update, Delete) operations. While the package name uses ABCD, all internal APIs and documentation use CRUD terminology for familiarity and consistency with common programming patterns.
@@ -15,6 +17,7 @@ A powerful React hook for managing ABCD (or CRUD) operations with optimistic upd
15
17
  - ⏳ Debounced sync with configurable delays
16
18
  - 🔄 Sync queue management with pause/resume/retry
17
19
  - 🎨 Context-based filtering and pagination
20
+ - 🔌 End-to-end type-safe client-server sync utilities
18
21
 
19
22
  ## Installation
20
23
 
@@ -88,22 +91,23 @@ function TodoList() {
88
91
  The `Config` object defines how your data is fetched, synced, and managed:
89
92
 
90
93
  ```typescript
91
- type Config<T, C> = {
92
- id: string; // Unique identifier for this collection
93
- initialContext: C; // Initial context (filters, pagination, etc.)
94
- getId: (item: T) => string; // Extract ID from item
94
+ type Config<T extends object, C> = {
95
+ id: string; // Unique identifier for this collection
96
+ initialContext: C; // Initial context (filters, pagination, etc.)
97
+ getId: (item: T) => string; // Extract ID from item
98
+ setId?: (item: T, newId: string) => T; // Optional: for ID remapping on create
95
99
 
96
100
  // Optional sync configuration
97
- syncDebounce?: number; // Debounce delay for sync (default: 300ms)
98
- syncRetries?: number; // Max retry attempts (default: 3)
101
+ syncDebounce?: number; // Debounce delay for sync (default: 300ms)
102
+ syncRetries?: number; // Max retry attempts (default: 3)
99
103
 
100
104
  // Optional cache configuration
101
- cacheCapacity?: number; // Max cache entries (default: 10)
102
- cacheTtl?: number; // Cache TTL in ms (default: 60000)
105
+ cacheCapacity?: number; // Max cache entries (default: 10)
106
+ cacheTtl?: number; // Cache TTL in ms (default: 60000)
103
107
 
104
108
  // Required handlers
105
109
  onFetch: (context: C, signal: AbortSignal) => Promise<T[]>;
106
- onSync: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;
110
+ onSync?: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;
107
111
  };
108
112
  ```
109
113
 
@@ -119,7 +123,6 @@ The `useCrud` hook returns:
119
123
  loading: boolean; // Fetch loading state
120
124
  syncing: boolean; // Sync in progress
121
125
  syncQueue: SyncQueueState<T>; // Sync queue state
122
- syncState: SyncState; // Overall sync state
123
126
 
124
127
  // Item operations (optimistic)
125
128
  create: (item: T) => void;
@@ -141,126 +144,64 @@ The `useCrud` hook returns:
141
144
 
142
145
  ## Examples
143
146
 
144
- The repository includes comprehensive examples demonstrating various use cases:
145
-
146
- ### 1. Full CRUD Operations (Products Example)
147
-
148
- Demonstrates complete CRUD functionality with:
149
- - Create, read, update, delete operations
150
- - Category filtering and search
151
- - Sync queue management
152
- - Error handling with retries
153
- - Per-item status indicators
154
-
155
- ```typescript
156
- const ProductsConfig: Config<Product, ProductContext> = {
157
- id: "products",
158
- initialContext: { page: 1, limit: 10 },
159
- getId: (item) => item.id,
160
-
161
- onFetch: async (context, signal) => {
162
- const params = new URLSearchParams({
163
- page: String(context.page),
164
- limit: String(context.limit),
165
- });
166
- if (context.category) params.append("category", context.category);
167
- if (context.search) params.append("search", context.search);
147
+ The repository includes examples demonstrating various use cases:
168
148
 
169
- const response = await fetch(`/api/products?${params}`, { signal });
170
- return (await response.json()).items;
171
- },
149
+ - **Products** - Full CRUD with filtering, search, and error handling
150
+ - **Pagination** - Context-based pagination with dynamic page size
151
+ - **Optimistic Updates** - Comments with instant UI feedback and sync queue visualization
152
+ - **Blog Post** - Simple single-item editing
153
+ - **Todo List** - Basic list operations
172
154
 
173
- onSync: async (changes, signal) => {
174
- // Handle batch sync operations
175
- },
176
- };
177
- ```
155
+ Run locally: `bun run dev` or `npm run dev` and visit `http://localhost:5173`
178
156
 
179
- **Key features:**
180
- - Filtering by category
181
- - Text search
182
- - Pause/resume sync
183
- - Retry failed operations
184
- - Visual status indicators
157
+ ## Advanced Usage
185
158
 
186
- ### 2. Pagination (Users Example)
159
+ ### Individual Item Management
187
160
 
188
- Shows context-based pagination with:
189
- - Dynamic page size selection
190
- - Next/previous navigation
191
- - Context updates trigger re-fetch
161
+ Use `getItem()` with `useItem()` for managing individual items:
192
162
 
193
163
  ```typescript
194
- interface UserContext {
195
- page: number;
196
- limit: number;
164
+ import { useCrud, useItem } from "use-abcd";
165
+
166
+ function ProductList() {
167
+ const { items, getItem } = useCrud(ProductsConfig);
168
+
169
+ return (
170
+ <div>
171
+ {Array.from(items.keys()).map((id) => (
172
+ <ProductItem key={id} item={getItem(id)} />
173
+ ))}
174
+ </div>
175
+ );
197
176
  }
198
177
 
199
- const { items, context, setContext } = useCrud<User, UserContext>(UsersConfig);
200
-
201
- // Change page
202
- setContext((draft) => {
203
- draft.page += 1;
204
- });
205
-
206
- // Change items per page
207
- setContext((draft) => {
208
- draft.limit = 20;
209
- draft.page = 1; // Reset to first page
210
- });
178
+ function ProductItem({ item }: { item: Item<Product, ProductContext> }) {
179
+ const { data, status, update, remove, exists } = useItem(item);
180
+
181
+ if (!exists) return null;
182
+
183
+ return (
184
+ <div>
185
+ <h3>{data?.name}</h3>
186
+ <p>Status: {status?.status || "synced"}</p>
187
+ <button onClick={() => update((draft) => { draft.stock += 1; })}>
188
+ Add Stock
189
+ </button>
190
+ <button onClick={() => remove()}>Delete</button>
191
+ </div>
192
+ );
193
+ }
211
194
  ```
212
195
 
213
- **Key features:**
214
- - Configurable page size
215
- - Context-based pagination
216
- - Automatic re-fetch on context change
217
-
218
- ### 3. Optimistic Updates (Comments Example)
219
-
220
- Demonstrates the power of optimistic updates:
221
- - Instant UI feedback
222
- - Background synchronization
223
- - Sync queue visualization
224
- - Manual retry controls
225
- - Error state handling
226
-
227
- ```typescript
228
- const CommentsConfig: Config<Comment, CommentContext> = {
229
- id: "comments-optimistic",
230
- initialContext: { postId: "1" },
231
- getId: (item) => item.id,
232
- syncDebounce: 100, // Very short debounce for demo
233
-
234
- // ... handlers
235
- };
236
-
237
- // Create appears instantly in UI
238
- create({
239
- id: `temp-${Date.now()}`,
240
- text: "New comment",
241
- author: "You",
242
- createdAt: new Date().toISOString(),
243
- });
244
- ```
196
+ **Benefits:**
245
197
 
246
- **Key features:**
247
- - Immediate UI updates
248
- - Sync queue status display
249
- - Pause/resume synchronization
250
- - Per-item sync status
251
- - Manual retry for errors
198
+ - `useItem()` subscribes only to that specific item's changes
199
+ - React re-renders only when that item's data changes (automatic optimization via WeakMap cache)
200
+ - Clean separation of list and item concerns
252
201
 
253
- ### 4. Original Examples
202
+ ### Context-Based Filtering & Pagination
254
203
 
255
- The repository also includes the original simpler examples:
256
- - **Blog Post**: Single item editing with optimistic updates
257
- - **Todo List**: Simple list with toggle completion
258
-
259
- ## Advanced Usage
260
-
261
- ### Custom Context for Filtering
262
-
263
- Use context to manage filters, pagination, sorting, etc.:
204
+ Use context to manage filters, pagination, sorting:
264
205
 
265
206
  ```typescript
266
207
  interface ProductContext {
@@ -268,228 +209,272 @@ interface ProductContext {
268
209
  limit: number;
269
210
  category?: string;
270
211
  search?: string;
271
- sortBy?: "name" | "price";
272
212
  }
273
213
 
274
- const { context, setContext } = useCrud<Product, ProductContext>(config);
214
+ const { items, context, setContext } = useCrud<Product, ProductContext>(config);
275
215
 
276
- // Update multiple context fields
216
+ // Update context to refetch
277
217
  setContext((draft) => {
278
218
  draft.category = "electronics";
279
219
  draft.page = 1;
280
220
  });
281
221
  ```
282
222
 
283
- ### Monitoring Sync Queue
223
+ ### Sync Queue Monitoring
284
224
 
285
225
  Track pending changes and errors:
286
226
 
287
227
  ```typescript
288
228
  const { syncQueue, pauseSync, resumeSync, retrySync } = useCrud(config);
289
229
 
230
+ // Check queue state
290
231
  console.log({
291
232
  pending: syncQueue.queue.size,
292
233
  inFlight: syncQueue.inFlight.size,
293
234
  errors: syncQueue.errors.size,
294
- isPaused: syncQueue.isPaused,
295
- isSyncing: syncQueue.isSyncing,
296
235
  });
297
236
 
298
- // Pause sync temporarily
237
+ // Control sync
299
238
  pauseSync();
300
-
301
- // Resume sync
302
239
  resumeSync();
303
-
304
- // Retry specific item
305
- retrySync(itemId);
306
-
307
- // Retry all failed items
308
- retrySync();
309
- ```
310
-
311
- ### Per-Item Status
312
-
313
- Track the sync status of individual items:
314
-
315
- ```typescript
316
- const { getItemStatus } = useCrud(config);
317
-
318
- const status = getItemStatus(itemId);
319
- if (status) {
320
- console.log({
321
- type: status.type, // "create" | "update" | "delete"
322
- status: status.status, // "pending" | "syncing" | "success" | "error"
323
- retries: status.retries, // Number of retry attempts
324
- error: status.error, // Error message if failed
325
- });
326
- }
240
+ retrySync(); // Retry all failed items
241
+ retrySync(itemId); // Retry specific item
327
242
  ```
328
243
 
329
244
  ### ID Remapping for Optimistic Creates
330
245
 
331
- When creating items optimistically, you typically use a temporary ID (e.g., `temp-${Date.now()}`). After the server confirms the creation, it may assign a different permanent ID. The library automatically handles this ID remapping.
332
-
333
- **In your `onSync` handler**, return the server-assigned `newId` for create operations:
246
+ Handle temporary IDs that get replaced by server-assigned IDs:
334
247
 
335
248
  ```typescript
336
249
  onSync: async (changes, signal) => {
337
- const results: SyncResult[] = [];
338
-
339
250
  for (const change of changes) {
340
251
  if (change.type === "create") {
341
252
  const response = await fetch("/api/items", {
342
253
  method: "POST",
343
- headers: { "Content-Type": "application/json" },
344
254
  body: JSON.stringify(change.data),
345
255
  signal,
346
256
  });
347
-
348
- if (!response.ok) throw new Error("Failed to create");
349
-
350
257
  const data = await response.json();
351
- // Return newId to remap the temporary ID to the server-assigned ID
352
- results.push({
353
- id: change.id, // The temporary ID
258
+
259
+ // Return newId to remap temp ID to server ID
260
+ return {
261
+ id: change.id, // Temporary ID (e.g., "temp-123")
354
262
  status: "success",
355
- newId: data.id, // The server-assigned permanent ID
356
- });
263
+ newId: data.id, // Server-assigned ID (e.g., "456")
264
+ };
357
265
  }
358
266
  // ... handle update and delete
359
267
  }
360
-
361
- return results;
362
268
  };
363
269
  ```
364
270
 
365
- **What happens automatically:**
366
- 1. The item's key in the `items` Map is updated from `temp-123` to `server-456`
367
- 2. The item's `id` property is updated (assumes item has an `id` field)
368
- 3. Any `Item` references are updated to use the new ID
369
- 4. The UI re-renders with the correct permanent ID
271
+ The library automatically:
272
+
273
+ 1. Updates the item's key in the `items` Map
274
+ 2. Updates the item's `id` property
275
+ 3. Updates any `Item` references
276
+ 4. Triggers UI re-render
370
277
 
371
- **Custom ID field**: If your item uses a different property for the ID (not `id`), provide a `setId` function in your config:
278
+ ## End-to-End Type-Safe CRUD with createSyncClient & createSyncServer
279
+
280
+ Build a complete type-safe CRUD solution with minimal boilerplate:
281
+
282
+ ### Client Setup
372
283
 
373
284
  ```typescript
374
- const config: Config<MyItem, Context> = {
375
- getId: (item) => item.itemId,
376
- setId: (item, newId) => ({ ...item, itemId: newId }),
377
- // ...
285
+ import { useCrud, createSyncClientFromEndpoint } from "use-abcd";
286
+
287
+ interface User {
288
+ id: string;
289
+ name: string;
290
+ email: string;
291
+ }
292
+
293
+ interface UserQuery {
294
+ page: number;
295
+ limit: number;
296
+ search?: string;
297
+ }
298
+
299
+ const UserConfig: Config<User, UserQuery> = {
300
+ id: "users",
301
+ initialContext: { page: 1, limit: 10 },
302
+ getId: (user) => user.id,
303
+
304
+ // Use createSyncClientFromEndpoint for unified fetch + sync
305
+ ...createSyncClientFromEndpoint<User, UserQuery>("/api/users"),
378
306
  };
379
- ```
380
307
 
381
- ### Cache Control
308
+ function UserList() {
309
+ const { items, loading, create, update, remove, setContext } = useCrud(UserConfig);
310
+
311
+ return (
312
+ <div>
313
+ {loading ? <p>Loading...</p> : (
314
+ <>
315
+ {Array.from(items.values()).map((user) => (
316
+ <div key={user.id}>
317
+ <span>{user.name} - {user.email}</span>
318
+ <button onClick={() => update(user.id, (draft) => {
319
+ draft.name = "Updated Name";
320
+ })}>
321
+ Update
322
+ </button>
323
+ <button onClick={() => remove(user.id)}>Delete</button>
324
+ </div>
325
+ ))}
326
+ <button onClick={() => create({
327
+ id: `temp-${Date.now()}`,
328
+ name: "New User",
329
+ email: "new@example.com",
330
+ })}>
331
+ Add User
332
+ </button>
333
+ </>
334
+ )}
335
+ </div>
336
+ );
337
+ }
338
+ ```
382
339
 
383
- Control caching behavior:
340
+ ### Server Setup
384
341
 
385
342
  ```typescript
386
- const config: Config<T, C> = {
387
- // ...
388
- cacheCapacity: 20, // Store up to 20 cache entries
389
- cacheTtl: 30000, // Cache expires after 30 seconds
390
- };
343
+ import { createSyncServer, serverSyncSuccess } from "use-abcd/runtime/server";
391
344
 
392
- const { refresh } = useCrud(config);
345
+ // Define your handlers
346
+ const usersHandler = createSyncServer<User, UserQuery>({
347
+ fetch: async (query) => {
348
+ // Handle pagination and search
349
+ return db.users.findMany({
350
+ skip: (query.page - 1) * query.limit,
351
+ take: query.limit,
352
+ where: query.search ? { name: { contains: query.search } } : undefined,
353
+ });
354
+ },
393
355
 
394
- // Force refresh (bypass cache)
395
- await refresh();
396
- ```
356
+ create: async (data) => {
357
+ const user = await db.users.create({ data });
358
+ return serverSyncSuccess({ newId: user.id });
359
+ },
397
360
 
398
- ## Running Examples Locally
361
+ update: async (id, data) => {
362
+ await db.users.update({ where: { id }, data });
363
+ return serverSyncSuccess();
364
+ },
399
365
 
400
- The repository includes a development environment with MSW (Mock Service Worker) for testing:
366
+ delete: async (id) => {
367
+ await db.users.delete({ where: { id } });
368
+ return serverSyncSuccess();
369
+ },
370
+ });
401
371
 
402
- ```bash
403
- # Clone the repository
404
- git clone https://github.com/smtrd3/use-abcd
405
- cd use-abcd
372
+ // Use with your framework
373
+ // Next.js App Router
374
+ export const POST = usersHandler.handler;
406
375
 
407
- # Install dependencies
408
- bun install # or npm install
376
+ // Hono
377
+ app.post("/api/users", (c) => usersHandler.handler(c.req.raw));
409
378
 
410
- # Start development server
411
- bun run dev # or npm run dev
379
+ // Bun.serve
380
+ Bun.serve({
381
+ fetch(req) {
382
+ if (new URL(req.url).pathname === "/api/users") {
383
+ return usersHandler.handler(req);
384
+ }
385
+ },
386
+ });
412
387
  ```
413
388
 
414
- Visit `http://localhost:5173` to see the examples in action.
389
+ ### What You Get
415
390
 
416
- ### Available Examples:
391
+ - **Type safety**: Full TypeScript inference from data types to API calls
392
+ - **Automatic ID remapping**: Temporary IDs are replaced with server-assigned IDs
393
+ - **Batch operations**: Multiple changes are sent in a single request
394
+ - **Optimistic updates**: UI updates instantly, syncs in background
395
+ - **Error handling**: Failed operations are tracked and can be retried
396
+ - **Unified endpoint**: Single POST endpoint handles fetch + create/update/delete
417
397
 
418
- 1. **Products (Full CRUD)** - Complete CRUD operations with filtering
419
- 2. **Pagination** - Context-based pagination with users
420
- 3. **Optimistic Updates** - Comments with sync queue visualization
421
- 4. **Blog Post (Original)** - Simple single-item editing
422
- 5. **Todo (Original)** - Basic list operations
398
+ ### Request/Response Format
399
+
400
+ ```typescript
401
+ // Fetch + Sync in one request
402
+ POST /api/users
403
+ Body: {
404
+ query: { page: 1, limit: 10, search: "john" },
405
+ changes: [
406
+ { id: "temp-123", type: "create", data: { ... } },
407
+ { id: "456", type: "update", data: { ... } },
408
+ { id: "789", type: "delete", data: { ... } }
409
+ ]
410
+ }
411
+
412
+ Response: {
413
+ results: [...users], // Fetched items
414
+ syncResults: [ // Sync results
415
+ { id: "temp-123", status: "success", newId: "999" },
416
+ { id: "456", status: "success" },
417
+ { id: "789", status: "success" }
418
+ ]
419
+ }
420
+ ```
423
421
 
424
422
  ## API Reference
425
423
 
426
424
  ### Types
427
425
 
428
426
  ```typescript
429
- // Main configuration
430
- type Config<T, C> = {
427
+ type Config<T extends object, C> = {
431
428
  id: string;
432
429
  initialContext: C;
433
430
  getId: (item: T) => string;
434
- setId?: (item: T, newId: string) => T; // Optional: for ID remapping on create
431
+ setId?: (item: T, newId: string) => T;
435
432
  syncDebounce?: number;
436
433
  syncRetries?: number;
437
434
  cacheCapacity?: number;
438
435
  cacheTtl?: number;
439
436
  onFetch: (context: C, signal: AbortSignal) => Promise<T[]>;
440
- onSync: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;
437
+ onSync?: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;
441
438
  };
442
439
 
443
- // Change type for sync operations
444
440
  type Change<T> = {
445
441
  id: string;
446
442
  type: "create" | "update" | "delete";
447
443
  data: T;
448
444
  };
449
445
 
450
- // Sync result
451
446
  type SyncResult = {
452
447
  id: string;
453
448
  status: "success" | "error";
454
449
  error?: string;
455
- newId?: string; // For create operations: server-assigned ID to replace temp ID
450
+ newId?: string; // For creates: server-assigned ID
456
451
  };
457
452
 
458
- // Item status
459
453
  type ItemStatus = {
460
454
  type: "create" | "update" | "delete";
461
455
  status: "pending" | "syncing" | "success" | "error";
462
456
  retries: number;
463
457
  error?: string;
464
458
  } | null;
465
-
466
- // Sync queue state
467
- type SyncQueueState<T> = {
468
- queue: Map<string, Change<T>>; // Pending changes
469
- inFlight: Map<string, Change<T>>; // Currently syncing
470
- errors: Map<string, { error: string; retries: number }>;
471
- isPaused: boolean;
472
- isSyncing: boolean;
473
- };
474
459
  ```
475
460
 
476
461
  ## Best Practices
477
462
 
478
- 1. **Use Optimistic Updates**: Let users see changes immediately while syncing in the background
479
- 2. **Handle Errors Gracefully**: Show error states and provide retry mechanisms
480
- 3. **Configure Debouncing**: Adjust `syncDebounce` based on your use case
481
- 4. **Leverage Context**: Use context for filters, pagination, and search
482
- 5. **Monitor Sync Queue**: Display pending changes and errors to users
483
- 6. **Cache Wisely**: Configure `cacheTtl` and `cacheCapacity` based on your data freshness requirements
463
+ 1. **Use Optimistic Updates** - Let users see changes immediately while syncing in the background
464
+ 2. **Handle Errors Gracefully** - Show error states and provide retry mechanisms
465
+ 3. **Leverage Context** - Use context for filters, pagination, and search to trigger automatic refetches
466
+ 4. **Use getItem() + useItem()** - For individual item management with automatic React optimization
467
+ 5. **Monitor Sync Queue** - Display pending changes and errors to users for transparency
468
+ 6. **Use createSyncClient/Server** - For end-to-end type-safe CRUD with minimal boilerplate
484
469
 
485
470
  ## Architecture
486
471
 
487
472
  The library is built on several core concepts:
488
473
 
489
- - **Collection**: Manages the item collection, sync queue, and fetch handler
490
- - **SyncQueue**: Handles debounced synchronization with retry logic
491
- - **FetchHandler**: Manages data fetching with caching
492
- - **Item**: Represents individual items with their sync state
474
+ - **Collection** - Manages the item collection, sync queue, and fetch handler
475
+ - **SyncQueue** - Handles debounced synchronization with retry logic
476
+ - **FetchHandler** - Manages data fetching with caching
477
+ - **Item** - Represents individual items with WeakMap-based caching for React optimization
493
478
 
494
479
  All state updates use [Mutative](https://github.com/unadlib/mutative) for immutable updates, ensuring React can efficiently detect changes.
495
480
 
@@ -499,4 +484,4 @@ This is an alpha release. Please read the source code for a deeper understanding
499
484
 
500
485
  ## License
501
486
 
502
- MIT
487
+ MIT
@@ -1,5 +1,6 @@
1
1
  import { Draft } from 'mutative';
2
2
  import { Item } from './item';
3
+ import { Node } from './node';
3
4
  import { Config, SyncState, Mutator, ItemStatus, SyncQueueState, FetchState } from './types';
4
5
  export type CollectionState<T, C> = {
5
6
  context: C;
@@ -11,17 +12,20 @@ export type CollectionState<T, C> = {
11
12
  fetchStatus: FetchState;
12
13
  fetchError?: string;
13
14
  };
14
- export declare class Collection<T, C> {
15
+ export declare class Collection<T extends object, C> {
15
16
  private static _cache;
16
- static get<T, C>(config: Config<T, C>): Collection<T, C>;
17
+ static get<T extends object, C>(config: Config<T, C>): Collection<T, C>;
17
18
  static clear(id: string): void;
18
19
  static clearAll(): void;
20
+ static getById<T extends object, C>(id: string): Collection<T, C> | undefined;
19
21
  readonly id: string;
20
22
  readonly config: Config<T, C>;
21
23
  private _state;
22
24
  private _syncQueue;
23
25
  private _fetchHandler;
24
26
  private _itemCache;
27
+ private _nodeCache;
28
+ private _selectedNodeId;
25
29
  private _subscribers;
26
30
  private _hasInitialized;
27
31
  private _batchMode;
@@ -38,7 +42,12 @@ export declare class Collection<T, C> {
38
42
  update(id: string, mutate: (draft: Draft<T>) => void): void;
39
43
  remove(id: string): void;
40
44
  getItem(id: string): Item<T, C>;
41
- _releaseItem(id: string): void;
45
+ getNode<V extends object, NodeType = string>(id: string): Node<V, C, NodeType>;
46
+ batch(fn: () => void): void;
47
+ selectNode(id: string): void;
48
+ deselectNode(): void;
49
+ get selectedNodeId(): string | null;
50
+ get selectedNode(): Node<any, C> | null;
42
51
  setContext(patchContext: Mutator<C>): void;
43
52
  refresh(): Promise<void>;
44
53
  pauseSync(): void;
@@ -0,0 +1,2 @@
1
+ import { default as React } from 'react';
2
+ export declare const TreeEditor: React.NamedExoticComponent<object>;