snap-records 1.1.0
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 +471 -0
- package/dist/index.d.ts +322 -0
- package/dist/snap-records.css +1 -0
- package/dist/snap-records.css.map +1 -0
- package/dist/snap-records.es.js +7325 -0
- package/dist/snap-records.es.js.map +1 -0
- package/dist/snap-records.umd.js +2 -0
- package/dist/snap-records.umd.js.map +1 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# SnapRecords
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://github.com/lbassuncao/SnapRecords/blob/main/docs/SnapRecords.png?raw=true" alt="SnapRecords Logo" width="256">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/snap-records"><img src="https://img.shields.io/npm/v/snap-records.svg" alt="NPM Version"></a>
|
|
9
|
+
<a href="./docs/LICENSE.txt"><img src="https://img.shields.io/npm/l/snap-records.svg" alt="License"></a>
|
|
10
|
+
<a href="https://github.com/lbassuncao/SnapRecords/actions/workflows/ci.yml"><img src="https://github.com/lbassuncao/SnapRecords/actions/workflows/ci.yml/badge.svg" alt="Build Status"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
<p align="center" style="font-size: 1.15rem">
|
|
16
|
+
<strong><a href="./docs/CONFIG.md">Configuration</a></strong> |
|
|
17
|
+
<strong><a href="./docs/BUILD.md">Build Guide</a></strong> |
|
|
18
|
+
<strong><a href="./docs/KEYBOARD.md">Keyboard Navigation</a></strong> |
|
|
19
|
+
<strong><a href="./CONTRIBUTING.md">Contributing</a></strong> |
|
|
20
|
+
<strong><a href="./docs/LICENSE.txt">License</a></strong> |
|
|
21
|
+
<strong><a href="./docs/COC.md">Code of Conduct</a></strong>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<br>
|
|
25
|
+
|
|
26
|
+
**SnapRecords** is a powerful, flexible TypeScript-based data grid component for displaying, managing, and interacting with tabular data in web applications.
|
|
27
|
+
|
|
28
|
+
Inspired by [jQuery Dynatable](https://github.com/alfajango/jquery-dynatable), it modernizes the concept with type safety, enhanced features, and performance optimizations.
|
|
29
|
+
|
|
30
|
+
It supports server-side pagination, sorting, filtering, caching, multiple rendering modes, and accessibility, making it ideal for both simple and complex data-driven interfaces.
|
|
31
|
+
|
|
32
|
+
## Key Strengths
|
|
33
|
+
|
|
34
|
+
- **Multiple Rendering Modes**: Supports table (`TABLE`), list (`LIST`), and mobile-friendly card (`MOBILE_CARDS`) views, adapting to various devices and use cases.
|
|
35
|
+
- **Server-Side Data Handling**: Integrates with APIs for pagination, filtering, and sorting, with a 250ms debounce delay and retry mechanism (up to 3 attempts by default).
|
|
36
|
+
- **Caching Support**: Uses IndexedDB via Dexie for caching server responses when `useCache` is enabled, with a default 8-hour expiry and cleanup on destroy if `destroyOnUnload` is enabled.
|
|
37
|
+
- **Interactive Features**: Includes column resizing, drag-and-drop column reordering, and row selection with keyboard navigation (ArrowUp/Down, Enter/Space, PageUp/Down).
|
|
38
|
+
- **Accessibility**: Implements ARIA attributes (`aria-sort`, `aria-selected`, `aria-label`), keyboard navigation, and screen reader announcements for inclusive experiences.
|
|
39
|
+
- **State Persistence**: Persists UI state (column order, widths, filters, page, etc.) in `localStorage` when `persistState` is enabled.
|
|
40
|
+
- **Customizable Styling**: Provides built-in `light` and `dark` themes, plus a `default` theme that inherits styles from the host page via CSS Custom Properties (`--sr-...`). This allows for seamless integration with any design system.
|
|
41
|
+
- **Type Safety**: Written in TypeScript with generic typing for type-safe data and configuration.
|
|
42
|
+
- **Extensibility**: Offers lifecycle hooks (`preDataLoad`, `postDataLoad`, `preRender`, `postRender`, `selectionChanged`) and customizable renderer, event, state, URL, and cache managers.
|
|
43
|
+
- **Internationalization**: Supports multiple languages via JSON files in the `/lang` directory, managed by `TranslationManager`.
|
|
44
|
+
- **Performance Optimizations**: Includes lazy loading of media, preloading of next-page data, and efficient format caching with `lru-cache` (controlled by `formatCacheSize`).
|
|
45
|
+
|
|
46
|
+
## Getting Started
|
|
47
|
+
|
|
48
|
+
To quickly set up SnapRecords:
|
|
49
|
+
|
|
50
|
+
1. Install dependencies:
|
|
51
|
+
```bash
|
|
52
|
+
npm install dexie immer lru-cache
|
|
53
|
+
```
|
|
54
|
+
2. Include the compiled CSS:
|
|
55
|
+
```html
|
|
56
|
+
<link rel="stylesheet" href="/path/to/snap-records.css" />
|
|
57
|
+
```
|
|
58
|
+
3. Create a container:
|
|
59
|
+
```html
|
|
60
|
+
<div id="table-container"></div>
|
|
61
|
+
```
|
|
62
|
+
4. Initialize SnapRecords:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { SnapRecords, RowsPerPage } from './SnapRecords';
|
|
66
|
+
|
|
67
|
+
new SnapRecords('table-container', {
|
|
68
|
+
url: '[https://api.example.com/data](https://api.example.com/data)',
|
|
69
|
+
columns: ['id', 'name'],
|
|
70
|
+
rowsPerPage: RowsPerPage.DEFAULT,
|
|
71
|
+
// No theme specified, so it uses 'default' and inherits host page styles
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
### Prerequisites
|
|
78
|
+
|
|
79
|
+
- Node.js (version 20 or higher)
|
|
80
|
+
- TypeScript (version 5 or higher)
|
|
81
|
+
- A modern browser supporting IndexedDB for caching
|
|
82
|
+
|
|
83
|
+
### Dependencies
|
|
84
|
+
|
|
85
|
+
SnapRecords relies on the following runtime dependencies, which must be installed in your project:
|
|
86
|
+
|
|
87
|
+
- `dexie` (^4.0.11): For IndexedDB caching of server responses.
|
|
88
|
+
- `immer` (^10.1.1): For immutable state management.
|
|
89
|
+
- `lru-cache` (^11.1.0): For efficient caching of formatted cell values.
|
|
90
|
+
|
|
91
|
+
Install them with:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm install dexie immer lru-cache
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Steps
|
|
98
|
+
|
|
99
|
+
1. **Install Dependencies**:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install dexie immer lru-cache
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
2. **Add SnapRecords**: Copy the source files (`SnapRecords.ts`, `SnapApi.ts`, `SnapRenderer.ts`, `EventManager.ts`, `SnapRecordsDB.ts`, `Translations.ts`, `SnapOptions.ts`, `SnapTypes.ts`, `Configuration.ts`, `StateManager.ts`, `UrlManager.ts`, `CacheManager.ts`, `utils.ts`, and `scss/SnapRecords.scss`) into your project.
|
|
106
|
+
|
|
107
|
+
3. **Add Translation Files**: Place translation JSON files (e.g., `en_US.json`, `pt_PT.json`, `es_ES.json`) in the `/lang` directory within your application's public directory:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
public/
|
|
111
|
+
└── lang/
|
|
112
|
+
├── en_US.json
|
|
113
|
+
├── pt_PT.json
|
|
114
|
+
└── es_ES.json
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
4. **Include Styles**: Compile the SCSS file to CSS and include it in your application:
|
|
118
|
+
|
|
119
|
+
````bash
|
|
120
|
+
sass src/scss/SnapRecords.scss dist/snap-records.css --style=compressed --source-map
|
|
121
|
+
```html
|
|
122
|
+
<link rel="stylesheet" href="/path/to/snap-records.css">
|
|
123
|
+
````
|
|
124
|
+
|
|
125
|
+
5. **Import and Initialize**: Import SnapRecords and initialize it:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { SnapRecords, RenderType, RowsPerPage } from './SnapRecords';
|
|
129
|
+
|
|
130
|
+
const snapRecords = new SnapRecords('table-container', {
|
|
131
|
+
url: 'https://api.example.com/data',
|
|
132
|
+
columns: ['id', 'name', 'email'],
|
|
133
|
+
rowsPerPage: RowsPerPage.DEFAULT,
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Usage Examples
|
|
138
|
+
|
|
139
|
+
### Basic Example
|
|
140
|
+
|
|
141
|
+
A minimal setup with a table displaying user data:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { SnapRecords, RowsPerPage } from './SnapRecords';
|
|
145
|
+
|
|
146
|
+
const snapRecords = new SnapRecords('table-container', {
|
|
147
|
+
url: '/api/users',
|
|
148
|
+
columns: ['id', 'name', 'email'],
|
|
149
|
+
columnTitles: ['ID', 'Name', 'Email'],
|
|
150
|
+
rowsPerPage: RowsPerPage.TWENTY,
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Example with Row Selection and Custom Formatting
|
|
155
|
+
|
|
156
|
+
Enabling row selection, custom formatting, and disabling sorting on a column:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { SnapRecords, RenderType, RowsPerPage } from './SnapRecords';
|
|
160
|
+
|
|
161
|
+
const snapRecords = new SnapRecords('table-container', {
|
|
162
|
+
url: '/api/users',
|
|
163
|
+
columns: ['id', 'name', 'status', 'notes'],
|
|
164
|
+
columnTitles: ['ID', 'Name', 'Status', 'Notes'],
|
|
165
|
+
columnFormatters: {
|
|
166
|
+
status: (value) => `<span class="${value}">${String(value).toUpperCase()}</span>`,
|
|
167
|
+
},
|
|
168
|
+
rowsPerPage: RowsPerPage.FIFTY,
|
|
169
|
+
selectable: true,
|
|
170
|
+
headerCellClasses: ['col-id', 'col-name no-sorting', 'col-status', 'col-notes'],
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const api = snapRecords.getApi();
|
|
174
|
+
console.log(api.getSelectedRows());
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Complete Configuration Example
|
|
178
|
+
|
|
179
|
+
Using all available options:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { SnapRecords, RenderType, RowsPerPage } from './SnapRecords';
|
|
183
|
+
|
|
184
|
+
const snapRecords = new SnapRecords('table-container', {
|
|
185
|
+
url: 'https://api.example.com/data',
|
|
186
|
+
columns: ['id', 'name', 'email', 'status'],
|
|
187
|
+
columnTitles: ['ID', 'Name', 'Email', 'Status'],
|
|
188
|
+
columnFormatters: {
|
|
189
|
+
status: (value) => `<span class="${value}">${String(value).toUpperCase()}</span>`,
|
|
190
|
+
name: (value) => String(value).toLowerCase(),
|
|
191
|
+
},
|
|
192
|
+
format: RenderType.TABLE,
|
|
193
|
+
rowsPerPage: RowsPerPage.TWENTY,
|
|
194
|
+
useCache: true,
|
|
195
|
+
usePushState: true,
|
|
196
|
+
language: 'pt_PT',
|
|
197
|
+
headerCellClasses: ['id-col', 'name-col no-sorting', 'email-col', 'status-col'],
|
|
198
|
+
cacheExpiry: 7200000,
|
|
199
|
+
selectable: true,
|
|
200
|
+
lifecycleHooks: {
|
|
201
|
+
preDataLoad: (params) => console.log('Fetching:', params),
|
|
202
|
+
postDataLoad: (data) => console.log('Loaded:', data),
|
|
203
|
+
preRender: () => console.log('Rendering...'),
|
|
204
|
+
postRender: () => console.log('Render complete'),
|
|
205
|
+
selectionChanged: (rows) => console.log('Selected:', rows),
|
|
206
|
+
},
|
|
207
|
+
theme: 'dark',
|
|
208
|
+
draggableColumns: true,
|
|
209
|
+
prevButton: {
|
|
210
|
+
text: '<i class="fa fa-arrow-left"></i> Previous',
|
|
211
|
+
isHtml: true,
|
|
212
|
+
template: (page) => `<span>Back to page ${page}</span>`,
|
|
213
|
+
},
|
|
214
|
+
nextButton: {
|
|
215
|
+
text: 'Next',
|
|
216
|
+
isHtml: false,
|
|
217
|
+
template: (page) => `Next: ${page}`,
|
|
218
|
+
},
|
|
219
|
+
retryAttempts: 5,
|
|
220
|
+
preloadNextPage: true,
|
|
221
|
+
persistState: true,
|
|
222
|
+
destroyOnUnload: true,
|
|
223
|
+
debug: true,
|
|
224
|
+
lazyLoadMedia: true,
|
|
225
|
+
formatCacheSize: 1000,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const api = snapRecords.getApi();
|
|
229
|
+
api.search({ status: 'active' }, true);
|
|
230
|
+
api.gotoPage(2);
|
|
231
|
+
api.setTheme('light');
|
|
232
|
+
api.setRenderMode(RenderType.MOBILE_CARDS);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Configuration Options
|
|
236
|
+
|
|
237
|
+
The `SnapRecordsOptions<T>` interface defines all configuration options. Key options include (see `config.md` for full details):
|
|
238
|
+
|
|
239
|
+
- `url` (string, required): API URL for data fetching.
|
|
240
|
+
- `columns` (string[], required): Column keys to display.
|
|
241
|
+
- `columnTitles` (string[]): Custom header titles.
|
|
242
|
+
- `columnFormatters` ({ [key: string]: (value, row) => string }): Custom cell formatters, cached with `lru-cache`.
|
|
243
|
+
- `format` (RenderType): Rendering mode (`TABLE`, `LIST`, `MOBILE_CARDS`). Default: `TABLE`.
|
|
244
|
+
- `rowsPerPage` (RowsPerPage): Rows per page (10, 20, 50, 100, 250, 500, 1000). Default: 10.
|
|
245
|
+
- `useCache` (boolean): Enables IndexedDB caching. Default: `false`.
|
|
246
|
+
- `usePushState` (boolean): Updates browser URL with state. Default: `false`.
|
|
247
|
+
- `language` (string): UI language. Default: `en_US`.
|
|
248
|
+
- `headerCellClasses` (string[]): Header CSS classes, with `no-sorting` to disable sorting.
|
|
249
|
+
- `selectable` (boolean): Enables row selection. Default: `false`.
|
|
250
|
+
- `draggableColumns` (boolean): Enables column drag-and-drop. Default: `false`.
|
|
251
|
+
- `persistState` (boolean): Saves state to `localStorage`. Default: `false`.
|
|
252
|
+
- `destroyOnUnload` (boolean): Destroys instance on window unload. Default: `true`.
|
|
253
|
+
- `debug` (boolean): Enables debug logs. Default: `false`.
|
|
254
|
+
- `lazyLoadMedia` (boolean): Enables lazy loading for images. Default: `false`.
|
|
255
|
+
- `formatCacheSize` (number): Sets the maximum size of the LRU format cache. Default: 500.
|
|
256
|
+
- `lifecycleHooks` (LifecycleHooks<T>): Callbacks for lifecycle events.
|
|
257
|
+
- `prevButton`, `nextButton`: Customizes pagination buttons with text, HTML, or templates.
|
|
258
|
+
|
|
259
|
+
## API Methods
|
|
260
|
+
|
|
261
|
+
The `SnapApi` class provides methods for interacting with the component:
|
|
262
|
+
|
|
263
|
+
- `search(filters: Record<string, string>, merge?: boolean): void` - Applies filters and reloads data.
|
|
264
|
+
- `updateParams(params: Partial<Pick<SnapRecordsState<T>, 'currentPage' | 'rowsPerPage' | 'filters' | 'sortConditions'>>): void` - Updates multiple parameters.
|
|
265
|
+
- `reset(): void` - Clears filters, sorting, and state.
|
|
266
|
+
- `refresh(): void` - Reloads current data view.
|
|
267
|
+
- `gotoPage(page: number): void` - Navigates to a page.
|
|
268
|
+
- `setTheme(theme: 'light' | 'dark' | 'default'): void` - Sets the theme.
|
|
269
|
+
- `setRenderMode(mode: RenderType): void` - Changes rendering mode.
|
|
270
|
+
- `setRowsPerPage(newRowsPerPage: RowsPerPage): void` - Sets rows per page.
|
|
271
|
+
- `setLanguage(newLanguage: string): Promise<void>` - Sets UI language.
|
|
272
|
+
- `getData(): ReadonlyArray<T>` - Returns current data.
|
|
273
|
+
- `getTotals(): { totalRecords: number }` - Returns total records.
|
|
274
|
+
- `getSelectedRows(): T[]` - Returns selected rows.
|
|
275
|
+
- `clearSelection(): void` - Clears row selections.
|
|
276
|
+
- `destroy(): void` - Destroys the instance, clearing elements and cache.
|
|
277
|
+
|
|
278
|
+
Example:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const api = snapRecords.getApi();
|
|
282
|
+
api.search({ status: 'active' }, true);
|
|
283
|
+
api.gotoPage(2);
|
|
284
|
+
api.setRenderMode(RenderType.LIST);
|
|
285
|
+
api.clearSelection();
|
|
286
|
+
api.destroy();
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Styling
|
|
290
|
+
|
|
291
|
+
Customize styles via `src/scss/SnapRecords.scss`. The compiled `snap-records.css` must be included in your application:
|
|
292
|
+
|
|
293
|
+
```html
|
|
294
|
+
<link rel="stylesheet" href="/path/to/snap-records.css" />
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Key classes:
|
|
298
|
+
|
|
299
|
+
- `.snap-records`: Table container.
|
|
300
|
+
- `.snap-list`: List view container.
|
|
301
|
+
- `.snap-mobile-cards-container`: Mobile cards container.
|
|
302
|
+
- `.theme-light`, `.theme-dark`, `.theme-default`: Theme classes.
|
|
303
|
+
- `.snap-column-resize-handle`: Column resize handle.
|
|
304
|
+
- `.snap-draggable-column`: Draggable column indicator.
|
|
305
|
+
- `.snap-current-row`, `.snap-selected`: Row highlighting for navigation and selection.
|
|
306
|
+
|
|
307
|
+
Override styles in your CSS as needed.
|
|
308
|
+
|
|
309
|
+
## Accessibility
|
|
310
|
+
|
|
311
|
+
SnapRecords prioritizes accessibility:
|
|
312
|
+
|
|
313
|
+
- **ARIA Attributes**: Supports `aria-sort`, `aria-selected`, `aria-label` for table, list, and card modes.
|
|
314
|
+
- **Keyboard Navigation**: ArrowUp/Down for row navigation, Enter/Space for selection, PageUp/Down for pagination (see `keyboard.md`).
|
|
315
|
+
- **Screen Reader Support**: Announces updates (e.g., row selection, mode changes) via ARIA live regions.
|
|
316
|
+
|
|
317
|
+
## State Management
|
|
318
|
+
|
|
319
|
+
The `SnapRecordsState` interface manages state, including:
|
|
320
|
+
|
|
321
|
+
- Current page, rows per page, filters, sort conditions.
|
|
322
|
+
- Column order, widths, titles.
|
|
323
|
+
- Data, total records, format, language, theme.
|
|
324
|
+
|
|
325
|
+
State is persisted to `localStorage` when `persistState` is `true`, managed by `StateManager.ts`.
|
|
326
|
+
|
|
327
|
+
## Internationalization
|
|
328
|
+
|
|
329
|
+
Translations are loaded from `/lang` JSON files (e.g., `en_US.json`) via `TranslationManager`. Add new languages by creating JSON files following the `Translation` interface:
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"errors": {
|
|
334
|
+
"generic": "An error occurred.",
|
|
335
|
+
"invalidConfig": "Invalid configuration: {reason}",
|
|
336
|
+
"containerNotFound": "Container with ID {id} not found.",
|
|
337
|
+
"dataLoadingFailed": "Failed to load data: {error}",
|
|
338
|
+
"renderFailed": "Failed to render: {error}"
|
|
339
|
+
},
|
|
340
|
+
"loading": "Loading...",
|
|
341
|
+
"totalRecords": "Total records: {total}",
|
|
342
|
+
"filteredRecords": "Filtered records: {total}",
|
|
343
|
+
"errorTitle": "Error",
|
|
344
|
+
"errorMessage": "An unexpected error occurred.",
|
|
345
|
+
"noDataAvailable": "No data available.",
|
|
346
|
+
"previous": "Previous",
|
|
347
|
+
"next": "Next",
|
|
348
|
+
"retry": "Retry",
|
|
349
|
+
"pagination": {
|
|
350
|
+
"showingRecords": "Showing {start} to {end} of {total} records"
|
|
351
|
+
},
|
|
352
|
+
"currentPage": "Page {page}",
|
|
353
|
+
"jumpToPage": "Jump to page",
|
|
354
|
+
"pageNavigation": "Page navigation",
|
|
355
|
+
"sortAscending": "Sort ascending",
|
|
356
|
+
"sortDescending": "Sort descending",
|
|
357
|
+
"removeSort": "Remove sort",
|
|
358
|
+
"rowSelected": "Row selected",
|
|
359
|
+
"rowDeselected": "Row deselected",
|
|
360
|
+
"columnResizeHandle": "Resize column",
|
|
361
|
+
"dragColumn": "Drag column {col}",
|
|
362
|
+
"loadMore": "Load more"
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Troubleshooting
|
|
367
|
+
|
|
368
|
+
Common issues and solutions:
|
|
369
|
+
|
|
370
|
+
- **"Container with ID 'table-container' not found"**:
|
|
371
|
+
Ensure the container element exists in the DOM before initializing SnapRecords:
|
|
372
|
+
|
|
373
|
+
```html
|
|
374
|
+
<div id="table-container"></div>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
- **"Translation file for pt_PT not found"**:
|
|
378
|
+
Verify that `/lang/pt_PT.json` is in your public directory and accessible via HTTP.
|
|
379
|
+
|
|
380
|
+
- **Styles not applied**:
|
|
381
|
+
Ensure `snap-records.css` is included in your HTML or bundler:
|
|
382
|
+
|
|
383
|
+
```html
|
|
384
|
+
<link rel="stylesheet" href="/path/to/snap-records.css" />
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
- **Data not rendering**:
|
|
388
|
+
Confirm that the server response includes a unique `id` field for each row, as required by the `Identifiable` interface:
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"data": [
|
|
393
|
+
{ "id": 1, "name": "John" },
|
|
394
|
+
{ "id": 2, "name": "Jane" }
|
|
395
|
+
],
|
|
396
|
+
"totalRecords": 2
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
- **Keyboard navigation not working**:
|
|
401
|
+
Ensure `selectable: true` for row navigation and that the container is focused (`snapRecords.container.focus()`).
|
|
402
|
+
|
|
403
|
+
## Development
|
|
404
|
+
|
|
405
|
+
### Building
|
|
406
|
+
|
|
407
|
+
Compile TypeScript and SCSS:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
npm run build
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
This runs `npm run build:js` (for `tsc --noEmit` and `vite build`) and `npm run build:css` (for SCSS compilation with source maps).
|
|
414
|
+
|
|
415
|
+
### Testing
|
|
416
|
+
|
|
417
|
+
Tests are in the `tests/` directory, using Jest with JSDOM. `tests/SnapRecords.test.ts` covers initialization, API methods, user interactions (sorting, resizing, drag-and-drop), and rendering modes. Run tests with:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
npm test
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Extending
|
|
424
|
+
|
|
425
|
+
Add custom translations by creating a JSON file in `/lang`:
|
|
426
|
+
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"loading": "Chargement...",
|
|
430
|
+
"errors": {
|
|
431
|
+
"generic": "Une erreur est survenue."
|
|
432
|
+
// ...
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Customize rendering or event handling by providing custom `renderer`, `eventManager`, `stateManager`, `urlManager`, or `cacheManager` in the options.
|
|
438
|
+
|
|
439
|
+
## Additional Notes
|
|
440
|
+
|
|
441
|
+
- **Data Requirement: Unique `id` Field**: The data returned from the server must include a unique `id` field for each row, as required by the `Identifiable` interface in `SnapTypes.ts`. This `id` (string or number) is used by the plugin’s diffing mechanism to efficiently track and reconcile rows during rendering. The diffing process, implemented in `SnapRenderer.ts` (e.g., `#reconcileItems`), relies on this unique identifier to map existing DOM elements to data rows, ensuring accurate updates and preventing duplication or loss of data. For example, a server response should look like:
|
|
442
|
+
|
|
443
|
+
```json
|
|
444
|
+
{
|
|
445
|
+
"data": [
|
|
446
|
+
{ "id": 1, "name": "John", "email": "john@example.com" },
|
|
447
|
+
{ "id": 2, "name": "Jane", "email": "jane@example.com" }
|
|
448
|
+
],
|
|
449
|
+
"totalRecords": 2
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Failure to include a unique `id` may result in rendering errors or inconsistent behavior.
|
|
454
|
+
|
|
455
|
+
- **CSS Requirement**: The compiled `snap-records.css` file is required for proper styling of the table, list, or mobile card views, including support for column resizing, drag-and-drop, and row highlighting.
|
|
456
|
+
|
|
457
|
+
## Contributing
|
|
458
|
+
|
|
459
|
+
1. Fork the repository.
|
|
460
|
+
2. Create a feature branch (`git checkout -b feature/new-feature`).
|
|
461
|
+
3. Commit changes (`git commit -m 'Add new feature'`).
|
|
462
|
+
4. Push to the branch (`git push origin feature/new-feature`).
|
|
463
|
+
5. Open a pull request.
|
|
464
|
+
|
|
465
|
+
## License
|
|
466
|
+
|
|
467
|
+
MIT License. See [`LICENSE`](./docs/LICENSE.txt) for details.
|
|
468
|
+
|
|
469
|
+
## Support
|
|
470
|
+
|
|
471
|
+
For issues, feature requests, or questions, please open an issue on the repository or contact the maintainer.
|