@tachui/data 0.8.0-alpha
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/LICENSE +363 -0
- package/README.md +486 -0
- package/dist/List.js +481 -0
- package/dist/List.js.map +1 -0
- package/dist/Menu.js +466 -0
- package/dist/Menu.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/list/List.d.ts +213 -0
- package/dist/list/List.d.ts.map +1 -0
- package/dist/list/index.d.ts +5 -0
- package/dist/list/index.d.ts.map +1 -0
- package/dist/list/index.js +7 -0
- package/dist/list/index.js.map +1 -0
- package/dist/menu/Menu.d.ts +159 -0
- package/dist/menu/Menu.d.ts.map +1 -0
- package/dist/menu/index.d.ts +5 -0
- package/dist/menu/index.d.ts.map +1 -0
- package/dist/menu/index.js +9 -0
- package/dist/menu/index.js.map +1 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# @tachui/data
|
|
2
|
+
|
|
3
|
+
> Data display and organization components for tachUI framework
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@tachui/data)
|
|
6
|
+
[](https://opensource.org/licenses/MPL-2.0)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
The tachUI data package provides essential components for displaying and organizing data including lists and menus with advanced features like virtual scrolling, contextual menus, and flexible content organization.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 📋 **Advanced Lists** - Virtual scrolling, sectioned data, selection modes, swipe actions
|
|
15
|
+
- 🎯 **Contextual Menus** - Dropdowns, positioning, keyboard navigation, nested submenus
|
|
16
|
+
- âš¡ **Performance Optimized** - Virtual scrolling for large datasets, efficient updates
|
|
17
|
+
- 🎨 **SwiftUI-inspired API** - Familiar component patterns and modifiers
|
|
18
|
+
- 🔧 **TypeScript-first** - Complete type safety with comprehensive interfaces
|
|
19
|
+
- 📱 **Responsive Design** - Adapts to different screen sizes and interaction patterns
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @tachui/core@0.8.0-alpha @tachui/data@0.8.0-alpha
|
|
25
|
+
# or
|
|
26
|
+
pnpm add @tachui/core@0.8.0-alpha @tachui/data@0.8.0-alpha
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Basic List
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { VStack, Text } from '@tachui/primitives'
|
|
35
|
+
import { List } from '@tachui/data'
|
|
36
|
+
|
|
37
|
+
const items = [
|
|
38
|
+
{ id: 1, name: 'Item 1', category: 'A' },
|
|
39
|
+
{ id: 2, name: 'Item 2', category: 'A' },
|
|
40
|
+
{ id: 3, name: 'Item 3', category: 'B' },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
const app = VStack({
|
|
44
|
+
children: [
|
|
45
|
+
List({
|
|
46
|
+
data: items,
|
|
47
|
+
renderItem: item => Text(item.name),
|
|
48
|
+
})
|
|
49
|
+
.modifier.padding(16)
|
|
50
|
+
.build(),
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Sectioned List with Headers
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { List } from '@tachui/data'
|
|
59
|
+
|
|
60
|
+
const sectionedList = List({
|
|
61
|
+
sections: [
|
|
62
|
+
{
|
|
63
|
+
id: 'favorites',
|
|
64
|
+
header: 'Favorites',
|
|
65
|
+
items: favoriteItems,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'recent',
|
|
69
|
+
header: 'Recent',
|
|
70
|
+
items: recentItems,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
renderItem: item => Text(item.name),
|
|
74
|
+
renderSectionHeader: section =>
|
|
75
|
+
Text(section.header).modifier.fontWeight('bold'),
|
|
76
|
+
}).build()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Contextual Menu
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { Menu } from '@tachui/data'
|
|
83
|
+
|
|
84
|
+
const menuItems = [
|
|
85
|
+
{ id: 'edit', title: 'Edit', action: () => console.log('Edit') },
|
|
86
|
+
{
|
|
87
|
+
id: 'duplicate',
|
|
88
|
+
title: 'Duplicate',
|
|
89
|
+
action: () => console.log('Duplicate'),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'delete',
|
|
93
|
+
title: 'Delete',
|
|
94
|
+
role: 'destructive',
|
|
95
|
+
action: () => console.log('Delete'),
|
|
96
|
+
},
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
const menu = Menu({
|
|
100
|
+
items: menuItems,
|
|
101
|
+
placement: 'bottom-start',
|
|
102
|
+
}).build()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Components
|
|
106
|
+
|
|
107
|
+
### List Component
|
|
108
|
+
|
|
109
|
+
Advanced list component with virtual scrolling, selection, and swipe actions.
|
|
110
|
+
|
|
111
|
+
#### Basic Usage
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { List } from '@tachui/data'
|
|
115
|
+
|
|
116
|
+
const list = List({
|
|
117
|
+
data: items,
|
|
118
|
+
renderItem: (item, index) => Text(`${index + 1}. ${item.name}`),
|
|
119
|
+
}).build()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Virtual Scrolling
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const virtualList = List({
|
|
126
|
+
data: largeDataset,
|
|
127
|
+
renderItem: item => Text(item.name),
|
|
128
|
+
virtualScrolling: {
|
|
129
|
+
enabled: true,
|
|
130
|
+
itemHeight: 50, // Fixed height for performance
|
|
131
|
+
overscan: 5, // Extra items to render
|
|
132
|
+
},
|
|
133
|
+
}).build()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Sectioned List
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const sectionedList = List({
|
|
140
|
+
sections: [
|
|
141
|
+
{
|
|
142
|
+
id: 'group1',
|
|
143
|
+
header: 'Group 1',
|
|
144
|
+
footer: '3 items',
|
|
145
|
+
items: group1Items,
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'group2',
|
|
149
|
+
header: 'Group 2',
|
|
150
|
+
items: group2Items,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
renderItem: item => Text(item.name),
|
|
154
|
+
renderSectionHeader: section =>
|
|
155
|
+
Text(section.header).modifier.fontWeight('bold'),
|
|
156
|
+
renderSectionFooter: section =>
|
|
157
|
+
section.footer ? Text(section.footer).modifier.fontSize(12) : undefined,
|
|
158
|
+
}).build()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Selection Modes
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const selectableList = List({
|
|
165
|
+
data: items,
|
|
166
|
+
renderItem: (item, index) => Text(item.name),
|
|
167
|
+
selectionMode: 'multiple', // 'none' | 'single' | 'multiple'
|
|
168
|
+
selectedItems: selectedItemsSignal,
|
|
169
|
+
onSelectionChange: selected => {
|
|
170
|
+
console.log('Selected items:', selected)
|
|
171
|
+
},
|
|
172
|
+
}).build()
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Swipe Actions
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const swipeableList = List({
|
|
179
|
+
data: items,
|
|
180
|
+
renderItem: item => Text(item.name),
|
|
181
|
+
leadingSwipeActions: item => [
|
|
182
|
+
{
|
|
183
|
+
id: 'favorite',
|
|
184
|
+
title: 'Favorite',
|
|
185
|
+
backgroundColor: '#FFD700',
|
|
186
|
+
icon: 'star',
|
|
187
|
+
onTap: () => favoriteItem(item),
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
trailingSwipeActions: item => [
|
|
191
|
+
{
|
|
192
|
+
id: 'delete',
|
|
193
|
+
title: 'Delete',
|
|
194
|
+
backgroundColor: '#FF3B30',
|
|
195
|
+
destructive: true,
|
|
196
|
+
onTap: () => deleteItem(item),
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
}).build()
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Menu Component
|
|
203
|
+
|
|
204
|
+
Contextual menu component with positioning and keyboard navigation.
|
|
205
|
+
|
|
206
|
+
#### Basic Dropdown Menu
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { Menu } from '@tachui/data'
|
|
210
|
+
|
|
211
|
+
const dropdownMenu = Menu({
|
|
212
|
+
items: [
|
|
213
|
+
{ id: 'new', title: 'New Document', action: () => createNew() },
|
|
214
|
+
{ id: 'open', title: 'Open...', action: () => openFile() },
|
|
215
|
+
{ id: 'separator', title: '' }, // Visual separator
|
|
216
|
+
{ id: 'exit', title: 'Exit', action: () => exitApp() },
|
|
217
|
+
],
|
|
218
|
+
placement: 'bottom-start',
|
|
219
|
+
}).build()
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Nested Submenus
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const nestedMenu = Menu({
|
|
226
|
+
items: [
|
|
227
|
+
{
|
|
228
|
+
id: 'file',
|
|
229
|
+
title: 'File',
|
|
230
|
+
submenu: [
|
|
231
|
+
{ id: 'new', title: 'New', action: () => createNew() },
|
|
232
|
+
{ id: 'open', title: 'Open', action: () => openFile() },
|
|
233
|
+
{ id: 'save', title: 'Save', action: () => saveFile() },
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: 'edit',
|
|
238
|
+
title: 'Edit',
|
|
239
|
+
submenu: [
|
|
240
|
+
{ id: 'undo', title: 'Undo', action: () => undo() },
|
|
241
|
+
{ id: 'redo', title: 'Redo', action: () => redo() },
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
}).build()
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Menu with Icons and Shortcuts
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
const advancedMenu = Menu({
|
|
252
|
+
items: [
|
|
253
|
+
{
|
|
254
|
+
id: 'save',
|
|
255
|
+
title: 'Save',
|
|
256
|
+
systemImage: 'square.and.arrow.down',
|
|
257
|
+
shortcut: '⌘S',
|
|
258
|
+
action: () => save(),
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: 'export',
|
|
262
|
+
title: 'Export...',
|
|
263
|
+
systemImage: 'arrow.up.doc',
|
|
264
|
+
submenu: [
|
|
265
|
+
{ id: 'pdf', title: 'PDF', action: () => exportPDF() },
|
|
266
|
+
{ id: 'png', title: 'PNG', action: () => exportPNG() },
|
|
267
|
+
],
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
placement: 'bottom-end',
|
|
271
|
+
}).build()
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Advanced Features
|
|
275
|
+
|
|
276
|
+
### Virtual Scrolling
|
|
277
|
+
|
|
278
|
+
For large datasets, enable virtual scrolling to maintain performance:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const virtualList = List({
|
|
282
|
+
data: largeDataset, // 10,000+ items
|
|
283
|
+
renderItem: item => Text(item.name),
|
|
284
|
+
virtualScrolling: {
|
|
285
|
+
enabled: true,
|
|
286
|
+
itemHeight: 44, // Fixed height for performance
|
|
287
|
+
estimatedItemHeight: 44,
|
|
288
|
+
overscan: 10, // Extra items to render
|
|
289
|
+
threshold: 100, // Distance from viewport to trigger loading
|
|
290
|
+
},
|
|
291
|
+
}).build()
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Infinite Scrolling
|
|
295
|
+
|
|
296
|
+
Load data progressively as the user scrolls:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const [data, setData] = createSignal(initialData)
|
|
300
|
+
const [hasMore, setHasMore] = createSignal(true)
|
|
301
|
+
|
|
302
|
+
const infiniteList = List({
|
|
303
|
+
data,
|
|
304
|
+
renderItem: item => Text(item.name),
|
|
305
|
+
infiniteScrolling: {
|
|
306
|
+
enabled: true,
|
|
307
|
+
hasMore,
|
|
308
|
+
onLoadMore: async () => {
|
|
309
|
+
const newData = await loadMoreData()
|
|
310
|
+
setData([...data(), ...newData])
|
|
311
|
+
setHasMore(newData.length > 0)
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
}).build()
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Reactive Data
|
|
318
|
+
|
|
319
|
+
Lists automatically update when reactive data changes:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
const [items, setItems] = createSignal([
|
|
323
|
+
{ id: 1, name: 'Item 1' },
|
|
324
|
+
{ id: 2, name: 'Item 2' },
|
|
325
|
+
])
|
|
326
|
+
|
|
327
|
+
const reactiveList = List({
|
|
328
|
+
data: items, // Signal-based data
|
|
329
|
+
renderItem: item => Text(item.name),
|
|
330
|
+
}).build()
|
|
331
|
+
|
|
332
|
+
// Update data reactively
|
|
333
|
+
setItems([...items(), { id: 3, name: 'Item 3' }])
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Custom Item IDs
|
|
337
|
+
|
|
338
|
+
For better performance with large datasets:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const listWithIds = List({
|
|
342
|
+
data: items,
|
|
343
|
+
renderItem: item => Text(item.name),
|
|
344
|
+
getItemId: (item, index) => item.id || `item-${index}`,
|
|
345
|
+
}).build()
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Performance Optimization
|
|
349
|
+
|
|
350
|
+
### Bundle Size Optimization
|
|
351
|
+
|
|
352
|
+
Import only what you need for smaller bundles:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Import specific components
|
|
356
|
+
import { List } from '@tachui/data/list'
|
|
357
|
+
import { Menu } from '@tachui/data/menu'
|
|
358
|
+
|
|
359
|
+
// Or import everything
|
|
360
|
+
import { List, Menu } from '@tachui/data'
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Memory Management
|
|
364
|
+
|
|
365
|
+
The components automatically handle cleanup:
|
|
366
|
+
|
|
367
|
+
- Event listeners are properly removed
|
|
368
|
+
- Reactive effects are disposed
|
|
369
|
+
- Virtual scrolling caches are cleared
|
|
370
|
+
- DOM nodes are efficiently updated
|
|
371
|
+
|
|
372
|
+
### Rendering Performance
|
|
373
|
+
|
|
374
|
+
- **Virtual scrolling** for large lists
|
|
375
|
+
- **Reactive updates** only re-render changed items
|
|
376
|
+
- **Efficient diffing** for minimal DOM updates
|
|
377
|
+
- **Lazy loading** for images and content
|
|
378
|
+
|
|
379
|
+
## Accessibility
|
|
380
|
+
|
|
381
|
+
All components include comprehensive accessibility features:
|
|
382
|
+
|
|
383
|
+
- **ARIA labels** and descriptions
|
|
384
|
+
- **Keyboard navigation** support
|
|
385
|
+
- **Screen reader** compatibility
|
|
386
|
+
- **Focus management** for modals and menus
|
|
387
|
+
- **Semantic HTML** structure
|
|
388
|
+
|
|
389
|
+
## TypeScript Support
|
|
390
|
+
|
|
391
|
+
Full TypeScript support with comprehensive type definitions:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
interface CustomItem {
|
|
395
|
+
id: number
|
|
396
|
+
name: string
|
|
397
|
+
category: string
|
|
398
|
+
completed: boolean
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const typedList = List<CustomItem>({
|
|
402
|
+
data: items,
|
|
403
|
+
renderItem: item => Text(item.name),
|
|
404
|
+
// TypeScript knows item is CustomItem
|
|
405
|
+
}).build()
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Browser Support
|
|
409
|
+
|
|
410
|
+
- **Modern browsers** (Chrome, Firefox, Safari, Edge)
|
|
411
|
+
- **ES2020+** features supported
|
|
412
|
+
- **CSS Grid** and **Flexbox** required
|
|
413
|
+
- **Intersection Observer** for virtual scrolling
|
|
414
|
+
|
|
415
|
+
## API Reference
|
|
416
|
+
|
|
417
|
+
### List Props
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
interface ListProps<T = any> {
|
|
421
|
+
// Data
|
|
422
|
+
data?: T[] | Signal<T[]>
|
|
423
|
+
sections?: ListSection<T>[] | Signal<ListSection<T>[]>
|
|
424
|
+
|
|
425
|
+
// Rendering
|
|
426
|
+
renderItem: (item: T, index: number) => ComponentInstance
|
|
427
|
+
renderSectionHeader?: (
|
|
428
|
+
section: ListSection<T>,
|
|
429
|
+
index: number
|
|
430
|
+
) => ComponentInstance
|
|
431
|
+
renderSectionFooter?: (
|
|
432
|
+
section: ListSection<T>,
|
|
433
|
+
index: number
|
|
434
|
+
) => ComponentInstance
|
|
435
|
+
|
|
436
|
+
// Appearance
|
|
437
|
+
style?: ListStyle
|
|
438
|
+
separator?: boolean | ComponentInstance
|
|
439
|
+
|
|
440
|
+
// Selection
|
|
441
|
+
selectionMode?: SelectionMode
|
|
442
|
+
selectedItems?: Signal<Set<string | number>>
|
|
443
|
+
onSelectionChange?: (selectedItems: Set<string | number>) => void
|
|
444
|
+
|
|
445
|
+
// Item actions
|
|
446
|
+
leadingSwipeActions?: (item: T, index: number) => SwipeAction[]
|
|
447
|
+
trailingSwipeActions?: (item: T, index: number) => SwipeAction[]
|
|
448
|
+
onItemTap?: (item: T, index: number) => void
|
|
449
|
+
onItemLongPress?: (item: T, index: number) => void
|
|
450
|
+
|
|
451
|
+
// Virtual scrolling
|
|
452
|
+
virtualScrolling?: VirtualScrollConfig
|
|
453
|
+
|
|
454
|
+
// Infinite scrolling
|
|
455
|
+
infiniteScrolling?: InfiniteScrollConfig
|
|
456
|
+
|
|
457
|
+
// Performance
|
|
458
|
+
getItemId?: (item: T, index: number) => string | number
|
|
459
|
+
|
|
460
|
+
// Empty state
|
|
461
|
+
emptyState?: ComponentInstance
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Menu Props
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
interface MenuProps {
|
|
469
|
+
items: MenuItem[]
|
|
470
|
+
placement?: MenuPlacement
|
|
471
|
+
trigger?: ComponentInstance
|
|
472
|
+
isOpen?: Signal<boolean>
|
|
473
|
+
onOpenChange?: (isOpen: boolean) => void
|
|
474
|
+
keyboardNavigation?: boolean
|
|
475
|
+
closeOnSelect?: boolean
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Contributing
|
|
480
|
+
|
|
481
|
+
See the main [Contributing Guide](https://github.com/tach-UI/tachUI/blob/main/CONTRIBUTING.md) for information on contributing to tachUI data components.
|
|
482
|
+
|
|
483
|
+
## License
|
|
484
|
+
|
|
485
|
+
Mozilla Public License 2.0 - see [LICENSE](https://github.com/tach-UI/tachUI/blob/main/LICENSE) for details.</content>
|
|
486
|
+
</xai:function_call: write_file>./tachUI/packages/data/README.md
|