@operato/data-grist 9.0.0-beta.54 → 9.0.0-beta.56
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 +18 -0
- package/README.md +337 -44
- package/dist/src/data-grist.d.ts +12 -0
- package/dist/src/data-grist.js +42 -0
- package/dist/src/data-grist.js.map +1 -1
- package/dist/stories/accumulator-format.stories.js +1 -1
- package/dist/stories/accumulator-format.stories.js.map +1 -1
- package/dist/stories/append-position.stories.d.ts +8 -0
- package/dist/stories/append-position.stories.js +183 -0
- package/dist/stories/append-position.stories.js.map +1 -0
- package/dist/stories/barcode-input-filter.stories.js +1 -1
- package/dist/stories/barcode-input-filter.stories.js.map +1 -1
- package/dist/stories/bounded-select-filters.stories.js +1 -1
- package/dist/stories/bounded-select-filters.stories.js.map +1 -1
- package/dist/stories/bounded-select-record.stories.js +1 -1
- package/dist/stories/bounded-select-record.stories.js.map +1 -1
- package/dist/stories/click-event-custom.stories.js +1 -1
- package/dist/stories/click-event-custom.stories.js.map +1 -1
- package/dist/stories/click-event.stories.js +1 -1
- package/dist/stories/click-event.stories.js.map +1 -1
- package/dist/stories/creatable-only-column.stories.js +1 -1
- package/dist/stories/creatable-only-column.stories.js.map +1 -1
- package/dist/stories/default-filters.stories.js +1 -1
- package/dist/stories/default-filters.stories.js.map +1 -1
- package/dist/stories/dynamic-editable.stories.js +1 -1
- package/dist/stories/dynamic-editable.stories.js.map +1 -1
- package/dist/stories/empty-sorters.stories.js +1 -1
- package/dist/stories/empty-sorters.stories.js.map +1 -1
- package/dist/stories/explicit-fetch.stories.js +1 -1
- package/dist/stories/explicit-fetch.stories.js.map +1 -1
- package/dist/stories/fixed-column.stories.js +1 -1
- package/dist/stories/fixed-column.stories.js.map +1 -1
- package/dist/stories/grid-setting.stories.js +1 -1
- package/dist/stories/grid-setting.stories.js.map +1 -1
- package/dist/stories/grist-modes.stories.js +1 -1
- package/dist/stories/grist-modes.stories.js.map +1 -1
- package/dist/stories/group-header.stories.js +1 -1
- package/dist/stories/group-header.stories.js.map +1 -1
- package/dist/stories/record-view.stories.js +1 -1
- package/dist/stories/record-view.stories.js.map +1 -1
- package/dist/stories/textarea.stories.js +1 -1
- package/dist/stories/textarea.stories.js.map +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.js +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
- package/dist/stories/tree-column.stories.js +1 -1
- package/dist/stories/tree-column.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
@@ -3,6 +3,24 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
+
## [9.0.0-beta.56](https://github.com/hatiolab/operato/compare/v9.0.0-beta.55...v9.0.0-beta.56) (2025-03-30)
|
7
|
+
|
8
|
+
|
9
|
+
### :bug: Bug Fix
|
10
|
+
|
11
|
+
* add addRecordToTop method into ox-grist ([57851b0](https://github.com/hatiolab/operato/commit/57851b0847e8f591a059345950da39b94e8d5122))
|
12
|
+
* title for ox-grist stories and README.md ([38476a5](https://github.com/hatiolab/operato/commit/38476a5994b142f29205014aa0238a1724fd7de1))
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
## [9.0.0-beta.55](https://github.com/hatiolab/operato/compare/v9.0.0-beta.54...v9.0.0-beta.55) (2025-03-05)
|
17
|
+
|
18
|
+
**Note:** Version bump only for package @operato/data-grist
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
6
24
|
## [9.0.0-beta.54](https://github.com/hatiolab/operato/compare/v9.0.0-beta.53...v9.0.0-beta.54) (2025-03-04)
|
7
25
|
|
8
26
|
**Note:** Version bump only for package @operato/data-grist
|
package/README.md
CHANGED
@@ -1,95 +1,388 @@
|
|
1
|
-
#
|
1
|
+
# Data-Grist
|
2
2
|
|
3
|
-
|
3
|
+
Data-Grist is a powerful web component for displaying and manipulating data. It can present data in Grid, List, or Card formats and provides various features such as data sorting, filtering, editing, and more.
|
4
|
+
|
5
|
+
## Key Features
|
6
|
+
|
7
|
+
- **Multiple Display Modes**: Flexibly display the same data in grid, list, or card formats
|
8
|
+
- **Data Manipulation**: Add, modify, and delete records
|
9
|
+
- **Sorting and Filtering**: Single/multi-column sorting, various filtering options
|
10
|
+
- **Editing Capabilities**: Inline cell editing, validation
|
11
|
+
- **Pagination**: Standard paging and infinite scroll support
|
12
|
+
- **Selection**: Single/multiple record selection
|
13
|
+
- **State Tracking**: Track changed (dirty) records
|
14
|
+
- **Customization**: Support for various renderers, editors, and event handlers
|
15
|
+
- **Mobile Responsive**: Responsive design support
|
4
16
|
|
5
17
|
## Installation
|
6
18
|
|
7
19
|
```bash
|
8
|
-
npm
|
20
|
+
npm install @operato/data-grist
|
9
21
|
```
|
10
22
|
|
11
|
-
## Usage
|
23
|
+
## Basic Usage
|
12
24
|
|
13
25
|
```html
|
14
26
|
<script type="module">
|
15
|
-
import 'data-grist/
|
27
|
+
import '@operato/data-grist/ox-grist.js'
|
16
28
|
</script>
|
17
29
|
|
18
|
-
<
|
30
|
+
<ox-grist
|
31
|
+
.mode=${'GRID'}
|
32
|
+
.config=${gridConfig}
|
33
|
+
.fetchHandler=${fetchDataFunction}
|
34
|
+
></ox-grist>
|
19
35
|
```
|
20
36
|
|
21
|
-
##
|
37
|
+
## Modes
|
22
38
|
|
23
|
-
|
39
|
+
Data-Grist supports three display modes:
|
24
40
|
|
25
|
-
|
26
|
-
|
41
|
+
- **GRID**: Tabular data display (default)
|
42
|
+
- **LIST**: Mobile-friendly list format display
|
43
|
+
- **CARD**: Card format display
|
44
|
+
|
45
|
+
```javascript
|
46
|
+
// Set mode
|
47
|
+
gristElement.mode = 'GRID' // or 'LIST', 'CARD'
|
27
48
|
```
|
28
49
|
|
29
|
-
|
50
|
+
## Configuration (Config)
|
51
|
+
|
52
|
+
Data-Grist provides various configuration options.
|
53
|
+
|
54
|
+
```javascript
|
55
|
+
const config = {
|
56
|
+
columns: [
|
57
|
+
{
|
58
|
+
type: 'string',
|
59
|
+
name: 'name',
|
60
|
+
header: 'Name',
|
61
|
+
record: {
|
62
|
+
editable: true
|
63
|
+
},
|
64
|
+
sortable: true,
|
65
|
+
width: 150
|
66
|
+
}
|
67
|
+
// More columns...
|
68
|
+
],
|
69
|
+
rows: {
|
70
|
+
appendable: true, // Allow adding new records
|
71
|
+
editable: true, // Allow editing records
|
72
|
+
selectable: {
|
73
|
+
// Record selection settings
|
74
|
+
multiple: true // Allow multiple selections
|
75
|
+
}
|
76
|
+
},
|
77
|
+
pagination: {
|
78
|
+
infinite: false, // Use paging instead of infinite scroll
|
79
|
+
page: 1, // Starting page
|
80
|
+
limit: 20 // Records per page
|
81
|
+
}
|
82
|
+
// Additional settings...
|
83
|
+
}
|
84
|
+
```
|
30
85
|
|
31
|
-
|
32
|
-
|
86
|
+
### Column Types
|
87
|
+
|
88
|
+
```javascript
|
89
|
+
// String column
|
90
|
+
{
|
91
|
+
type: 'string',
|
92
|
+
name: 'firstName',
|
93
|
+
header: 'First Name'
|
94
|
+
}
|
95
|
+
|
96
|
+
// Number column
|
97
|
+
{
|
98
|
+
type: 'number',
|
99
|
+
name: 'age',
|
100
|
+
header: 'Age',
|
101
|
+
record: {
|
102
|
+
align: 'right'
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
// Boolean column
|
107
|
+
{
|
108
|
+
type: 'boolean',
|
109
|
+
name: 'isActive',
|
110
|
+
header: 'Active'
|
111
|
+
}
|
112
|
+
|
113
|
+
// Link column
|
114
|
+
{
|
115
|
+
type: 'link',
|
116
|
+
name: 'website',
|
117
|
+
header: 'Website',
|
118
|
+
record: {
|
119
|
+
options: {
|
120
|
+
href: (column, record) => record.url,
|
121
|
+
target: '_blank'
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
// Gutter column (row number, checkbox, button, etc.)
|
127
|
+
{
|
128
|
+
type: 'gutter',
|
129
|
+
gutterName: 'sequence' // 'row-selector', 'button', 'dirty', etc.
|
130
|
+
}
|
33
131
|
```
|
34
132
|
|
35
|
-
|
36
|
-
|
133
|
+
## Fetching Data
|
134
|
+
|
135
|
+
Data can be retrieved through the `fetchHandler` function.
|
136
|
+
|
137
|
+
```javascript
|
138
|
+
const fetchHandler = async params => {
|
139
|
+
const { page, limit, sorters, filters } = params
|
140
|
+
|
141
|
+
// Fetch data from server
|
142
|
+
const response = await fetch(`/api/data?page=${page}&limit=${limit}`)
|
143
|
+
const data = await response.json()
|
144
|
+
|
145
|
+
return {
|
146
|
+
total: data.total,
|
147
|
+
records: data.items
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
// Configure the grist
|
152
|
+
gristElement.fetchHandler = fetchHandler
|
37
153
|
```
|
38
154
|
|
39
|
-
|
155
|
+
## Record Manipulation API
|
40
156
|
|
41
|
-
|
42
|
-
|
157
|
+
### Adding Records
|
158
|
+
|
159
|
+
```javascript
|
160
|
+
// Add record at the end (default)
|
161
|
+
gristElement.addRecord({
|
162
|
+
name: 'John Doe',
|
163
|
+
age: 30
|
164
|
+
})
|
165
|
+
|
166
|
+
// Add record at the top
|
167
|
+
gristElement.addRecordToTop({
|
168
|
+
name: 'Jane Smith',
|
169
|
+
age: 25
|
170
|
+
})
|
43
171
|
```
|
44
172
|
|
45
|
-
|
173
|
+
### Record Selection
|
46
174
|
|
47
|
-
```
|
48
|
-
|
175
|
+
```javascript
|
176
|
+
// Get all selected records
|
177
|
+
const selectedRecords = gristElement.selected
|
178
|
+
|
179
|
+
// Set selection
|
180
|
+
gristElement.selected = [record1, record2]
|
181
|
+
|
182
|
+
// Select records using a selector function
|
183
|
+
gristElement.select(record => record.age > 30)
|
49
184
|
```
|
50
185
|
|
51
|
-
|
52
|
-
|
186
|
+
### Tracking Changed Records
|
187
|
+
|
188
|
+
```javascript
|
189
|
+
// Get modified records
|
190
|
+
const dirtyRecords = gristElement.dirtyRecords
|
191
|
+
|
192
|
+
// Check for changes
|
193
|
+
gristElement.checkDirties()
|
194
|
+
|
195
|
+
// Export changes as patches
|
196
|
+
const patches = gristElement.exportPatchList()
|
53
197
|
```
|
54
198
|
|
55
|
-
##
|
199
|
+
## Events
|
56
200
|
|
57
|
-
|
201
|
+
Data-Grist triggers various events.
|
58
202
|
|
59
|
-
```
|
60
|
-
|
203
|
+
```javascript
|
204
|
+
// Record selection change event
|
205
|
+
gristElement.addEventListener('select-record-change', e => {
|
206
|
+
const { records, added, removed } = e.detail
|
207
|
+
console.log('Selected records:', records)
|
208
|
+
})
|
209
|
+
|
210
|
+
// Field change event
|
211
|
+
gristElement.addEventListener('field-change', e => {
|
212
|
+
const { after, before, column, record, row } = e.detail
|
213
|
+
console.log('Changed field:', column.name, 'from', before, 'to', after)
|
214
|
+
})
|
215
|
+
|
216
|
+
// Record change event
|
217
|
+
gristElement.addEventListener('record-change', e => {
|
218
|
+
const { before, after, column, row } = e.detail
|
219
|
+
console.log('Record changed:', row)
|
220
|
+
})
|
61
221
|
```
|
62
222
|
|
63
|
-
|
223
|
+
## Advanced Features
|
64
224
|
|
65
|
-
|
66
|
-
|
225
|
+
### Column Accumulation Feature (Accumulator)
|
226
|
+
|
227
|
+
```javascript
|
228
|
+
{
|
229
|
+
type: 'number',
|
230
|
+
name: 'amount',
|
231
|
+
header: 'Amount',
|
232
|
+
accumulator: 'sum' // 'avg', 'count', 'min', 'max' or custom function
|
233
|
+
}
|
67
234
|
```
|
68
235
|
|
69
|
-
|
236
|
+
### Tree Structure Data
|
70
237
|
|
71
|
-
|
238
|
+
```javascript
|
239
|
+
const config = {
|
240
|
+
// ...
|
241
|
+
tree: {
|
242
|
+
childrenProperty: 'children', // Property name where child nodes are stored
|
243
|
+
expanded: true // Initial tree expansion state
|
244
|
+
}
|
245
|
+
}
|
246
|
+
```
|
72
247
|
|
73
|
-
|
74
|
-
|
248
|
+
### Grouped Headers
|
249
|
+
|
250
|
+
```javascript
|
251
|
+
const config = {
|
252
|
+
columns: [
|
253
|
+
// ...
|
254
|
+
{
|
255
|
+
type: 'string',
|
256
|
+
name: 'firstName',
|
257
|
+
header: 'First Name',
|
258
|
+
group: 'personalInfo'
|
259
|
+
},
|
260
|
+
{
|
261
|
+
type: 'string',
|
262
|
+
name: 'lastName',
|
263
|
+
header: 'Last Name',
|
264
|
+
group: 'personalInfo'
|
265
|
+
}
|
266
|
+
],
|
267
|
+
// ...
|
268
|
+
rows: {
|
269
|
+
// ...
|
270
|
+
groups: [
|
271
|
+
{
|
272
|
+
name: 'personalInfo',
|
273
|
+
title: 'Personal Information'
|
274
|
+
}
|
275
|
+
]
|
276
|
+
}
|
277
|
+
}
|
75
278
|
```
|
76
279
|
|
77
|
-
|
280
|
+
### User Settings Storage
|
281
|
+
|
282
|
+
```javascript
|
283
|
+
// Configure user settings provider
|
284
|
+
gristElement.personalConfigProvider = {
|
285
|
+
async load() {
|
286
|
+
// Load saved settings
|
287
|
+
return JSON.parse(localStorage.getItem('userGristConfig'))
|
288
|
+
},
|
289
|
+
async save(preference) {
|
290
|
+
// Save user settings
|
291
|
+
localStorage.setItem('userGristConfig', JSON.stringify(preference))
|
292
|
+
}
|
293
|
+
}
|
294
|
+
```
|
78
295
|
|
79
|
-
|
80
|
-
|
296
|
+
## Styling
|
297
|
+
|
298
|
+
Data-Grist can be styled through CSS variables.
|
299
|
+
|
300
|
+
```css
|
301
|
+
ox-grist {
|
302
|
+
--grid-header-background-color: #f5f5f5;
|
303
|
+
--grid-record-background-color: white;
|
304
|
+
--grid-record-odd-background-color: #f9f9f9;
|
305
|
+
--grid-header-color: #333;
|
306
|
+
--grid-record-hover-background-color: #e9e9e9;
|
307
|
+
}
|
81
308
|
```
|
82
309
|
|
83
|
-
##
|
310
|
+
## API Reference
|
311
|
+
|
312
|
+
### Properties
|
313
|
+
|
314
|
+
| Property | Type | Description |
|
315
|
+
| ----------------- | -------- | ------------------------------------- |
|
316
|
+
| `mode` | string | Display mode ('GRID', 'LIST', 'CARD') |
|
317
|
+
| `config` | object | Grist configuration object |
|
318
|
+
| `data` | object | Data to display |
|
319
|
+
| `selectedRecords` | array | Array of selected records |
|
320
|
+
| `explicitFetch` | boolean | Enable explicit data fetching |
|
321
|
+
| `fetchHandler` | function | Data fetching function |
|
322
|
+
| `fetchOptions` | object | Data fetching options |
|
323
|
+
| `filters` | array | Array of filters |
|
324
|
+
| `sorters` | array | Array of sorters |
|
325
|
+
| `pagination` | object | Pagination settings |
|
326
|
+
|
327
|
+
### Methods
|
328
|
+
|
329
|
+
| Method | Description |
|
330
|
+
| ------------------------------ | ------------------------------- |
|
331
|
+
| `fetch(reset)` | Fetch data |
|
332
|
+
| `addRecord(record)` | Add a record |
|
333
|
+
| `addRecordToTop(record)` | Add a record at the top |
|
334
|
+
| `deleteSelectedRecords(dirty)` | Delete selected records |
|
335
|
+
| `cloneSelectedRecords()` | Clone selected records |
|
336
|
+
| `checkDirties()` | Check for modified records |
|
337
|
+
| `undo()` | Undo last action |
|
338
|
+
| `redo()` | Redo undone action |
|
339
|
+
| `reset()` | Reset data |
|
340
|
+
| `commit()` | Commit changes |
|
341
|
+
| `select(selector, reset)` | Select records using a function |
|
342
|
+
| `exportPatchList(options)` | Export list of change patches |
|
343
|
+
| `exportRecords(options)` | Export record data |
|
344
|
+
|
345
|
+
## Examples
|
346
|
+
|
347
|
+
### Basic Grid
|
84
348
|
|
85
|
-
|
349
|
+
```html
|
350
|
+
<ox-grist
|
351
|
+
.mode=${'GRID'}
|
352
|
+
.config=${gridConfig}
|
353
|
+
.fetchHandler=${fetchData}
|
354
|
+
@record-change=${handleRecordChange}
|
355
|
+
></ox-grist>
|
356
|
+
```
|
86
357
|
|
87
|
-
|
358
|
+
### Editable Grid
|
88
359
|
|
89
|
-
|
360
|
+
```html
|
361
|
+
<ox-grist
|
362
|
+
.mode=${'GRID'}
|
363
|
+
.config=${{
|
364
|
+
columns: [/* column definitions */],
|
365
|
+
rows: {
|
366
|
+
appendable: true,
|
367
|
+
editable: true,
|
368
|
+
selectable: { multiple: true }
|
369
|
+
}
|
370
|
+
}}
|
371
|
+
.data=${{ records: initialData }}
|
372
|
+
></ox-grist>
|
373
|
+
```
|
90
374
|
|
91
|
-
|
92
|
-
|
375
|
+
### Add Row to Top Button
|
376
|
+
|
377
|
+
```html
|
378
|
+
<button @click="${() => gristRef.addRecordToTop()}">Add Row to Top</button>
|
379
|
+
<ox-grist id="my-grist"></ox-grist>
|
380
|
+
|
381
|
+
<script>
|
382
|
+
const gristRef = document.getElementById('my-grist')
|
383
|
+
</script>
|
93
384
|
```
|
94
385
|
|
95
|
-
|
386
|
+
## License
|
387
|
+
|
388
|
+
MIT
|
package/dist/src/data-grist.d.ts
CHANGED
@@ -324,6 +324,18 @@ export declare class DataGrist extends LitElement implements DataConsumer {
|
|
324
324
|
* an empty record with the `__dirty__` flag set to '+' will be added.
|
325
325
|
*/
|
326
326
|
addRecord(record?: GristRecord): void;
|
327
|
+
/**
|
328
|
+
* Adds a new record to the top of the data grid. The added record is marked as newly created
|
329
|
+
* by setting the `__dirty__` flag to '+'. This flag indicates that the record
|
330
|
+
* is in a "new" state and hasn't been committed to the main data yet.
|
331
|
+
*
|
332
|
+
* This method is useful when you need to add new records at the top of the grid
|
333
|
+
* without changing the default behavior of the appendable row.
|
334
|
+
*
|
335
|
+
* @param {GristRecord} [record] - An optional record to add. If no record is provided,
|
336
|
+
* an empty record with the `__dirty__` flag set to '+' will be added.
|
337
|
+
*/
|
338
|
+
addRecordToTop(record?: GristRecord): void;
|
327
339
|
/**
|
328
340
|
* Retrieves the search text used for filtering records.
|
329
341
|
*
|
package/dist/src/data-grist.js
CHANGED
@@ -830,6 +830,48 @@ let DataGrist = class DataGrist extends LitElement {
|
|
830
830
|
]
|
831
831
|
};
|
832
832
|
}
|
833
|
+
/**
|
834
|
+
* Adds a new record to the top of the data grid. The added record is marked as newly created
|
835
|
+
* by setting the `__dirty__` flag to '+'. This flag indicates that the record
|
836
|
+
* is in a "new" state and hasn't been committed to the main data yet.
|
837
|
+
*
|
838
|
+
* This method is useful when you need to add new records at the top of the grid
|
839
|
+
* without changing the default behavior of the appendable row.
|
840
|
+
*
|
841
|
+
* @param {GristRecord} [record] - An optional record to add. If no record is provided,
|
842
|
+
* an empty record with the `__dirty__` flag set to '+' will be added.
|
843
|
+
*/
|
844
|
+
addRecordToTop(record) {
|
845
|
+
const newRecord = {
|
846
|
+
...record,
|
847
|
+
__dirty__: '+'
|
848
|
+
};
|
849
|
+
this._data = {
|
850
|
+
...this._data,
|
851
|
+
records: [newRecord, ...this.dirtyData.records]
|
852
|
+
};
|
853
|
+
// 새 레코드에 포커스 및 스크롤 처리
|
854
|
+
setTimeout(() => {
|
855
|
+
// 그리드가 있는 경우 첫 번째 행에 포커스 설정
|
856
|
+
if (this.grist) {
|
857
|
+
// 포커스를 첫 번째 행으로 설정 (첫 번째 편집 가능한 셀로)
|
858
|
+
const focusableColumns = this.compiledConfig.columns.filter(column => column.type !== 'gutter' && !column.hidden && column.record.editable);
|
859
|
+
if (focusableColumns.length > 0) {
|
860
|
+
const columnIndex = this.compiledConfig.columns.indexOf(focusableColumns[0]);
|
861
|
+
this.grist.dispatchEvent(new CustomEvent('focus-change', {
|
862
|
+
bubbles: true,
|
863
|
+
composed: true,
|
864
|
+
detail: {
|
865
|
+
row: 0,
|
866
|
+
column: columnIndex
|
867
|
+
}
|
868
|
+
}));
|
869
|
+
}
|
870
|
+
// 스크롤을 맨 위로 이동
|
871
|
+
this.grist.scrollTop = 0;
|
872
|
+
}
|
873
|
+
}, 0);
|
874
|
+
}
|
833
875
|
/**
|
834
876
|
* Retrieves the search text used for filtering records.
|
835
877
|
*
|