@operato/data-grist 1.11.5 → 1.11.7

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/demo/data-grist-test.html +2 -1
  3. package/dist/src/configure/column-builder.js +8 -0
  4. package/dist/src/configure/column-builder.js.map +1 -1
  5. package/dist/src/data-grid/data-grid-accum-field.js +2 -15
  6. package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
  7. package/dist/src/data-grid/data-grid-field.js +4 -7
  8. package/dist/src/data-grid/data-grid-field.js.map +1 -1
  9. package/dist/src/data-grid/data-grid-header.d.ts +8 -5
  10. package/dist/src/data-grid/data-grid-header.js +131 -47
  11. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  12. package/dist/src/editors/ox-grist-editor-multiple-select.d.ts +1 -0
  13. package/dist/src/editors/ox-grist-editor-multiple-select.js +9 -1
  14. package/dist/src/editors/ox-grist-editor-multiple-select.js.map +1 -1
  15. package/dist/src/editors/ox-grist-editor.d.ts +1 -1
  16. package/dist/src/editors/ox-grist-editor.js +2 -2
  17. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  18. package/dist/src/renderers/ox-grist-renderer-tree.d.ts +8 -0
  19. package/dist/src/renderers/ox-grist-renderer-tree.js +134 -0
  20. package/dist/src/renderers/ox-grist-renderer-tree.js.map +1 -0
  21. package/dist/src/types.d.ts +2 -0
  22. package/dist/src/types.js.map +1 -1
  23. package/dist/stories/fixed-column.stories copy.d.ts +26 -0
  24. package/dist/stories/fixed-column.stories copy.js +448 -0
  25. package/dist/stories/fixed-column.stories copy.js.map +1 -0
  26. package/dist/stories/fixed-column.stories.js +3 -2
  27. package/dist/stories/fixed-column.stories.js.map +1 -1
  28. package/dist/stories/grist-modes.stories.js +2 -1
  29. package/dist/stories/grist-modes.stories.js.map +1 -1
  30. package/dist/stories/group-header.stories.d.ts +26 -0
  31. package/dist/stories/group-header.stories.js +473 -0
  32. package/dist/stories/group-header.stories.js.map +1 -0
  33. package/dist/stories/tree-column.stories.d.ts +26 -0
  34. package/dist/stories/tree-column.stories.js +310 -0
  35. package/dist/stories/tree-column.stories.js.map +1 -0
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +2 -2
  38. package/src/configure/column-builder.ts +8 -0
  39. package/src/data-grid/data-grid-accum-field.ts +2 -15
  40. package/src/data-grid/data-grid-field.ts +5 -9
  41. package/src/data-grid/data-grid-header.ts +148 -47
  42. package/src/editors/ox-grist-editor-multiple-select.ts +10 -1
  43. package/src/editors/ox-grist-editor.ts +2 -2
  44. package/src/types.ts +2 -0
  45. package/stories/fixed-column.stories.ts +3 -2
  46. package/stories/grist-modes.stories.ts +2 -1
  47. package/stories/group-header.stories.ts +505 -0
@@ -0,0 +1,505 @@
1
+ import '../src/index.js'
2
+ import '../src/filters/filters-form.js'
3
+ import '../src/sorters/sorters-control.js'
4
+ import '../src/record-view/record-creator.js'
5
+ import '@operato/popup/ox-popup-list.js'
6
+ import '@material/mwc-icon'
7
+
8
+ import { html, TemplateResult } from 'lit'
9
+
10
+ import {
11
+ ColumnConfig,
12
+ FetchHandler,
13
+ GristClassifier,
14
+ GristEventHandlerSet,
15
+ GristRecord,
16
+ ValidationCallback
17
+ } from '../src/types.js'
18
+
19
+ const fetchHandler: FetchHandler = async ({ page, limit }) => {
20
+ var total = 120993
21
+ var start = (page! - 1) * limit!
22
+
23
+ await new Promise(resolve => setTimeout(resolve, 500))
24
+
25
+ return {
26
+ total,
27
+ records: Array(limit! * page! > total ? total % limit! : limit)
28
+ .fill('')
29
+ .map((item, idx) => {
30
+ return {
31
+ id: String(idx),
32
+ name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
33
+ description: idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
34
+ email: idx % 2 ? `shnam-${start + idx + 1}@gmail.com` : `heartyoh-${start + idx + 1}@gmail.com`,
35
+ active: Math.round(Math.random() * 2) % 2 ? true : false,
36
+ barcode: idx % 2 ? `1234567890${start + idx + 1}` : `0987654321${start + idx + 1}`,
37
+ company:
38
+ idx % 2
39
+ ? {
40
+ id: '2',
41
+ name: 'HatioLAB',
42
+ description: `경기도 성남시-${start + idx + 1}`
43
+ }
44
+ : {
45
+ id: '3',
46
+ name: 'HatioSEA',
47
+ description: `말레이시아 세티아알람-${start + idx + 1}`
48
+ },
49
+ thumbnail:
50
+ idx % 4 === 0
51
+ ? '' /* no source */
52
+ : idx % 4 === 1
53
+ ? `http://www.hatiolab.com/assets/img/operato-biz3.png`
54
+ : idx % 4 === 2
55
+ ? `http://www.hatiolab.com/assets/img/thingsboard-30.png`
56
+ : `http://www.hatiolab.com/wrong-url.png` /* wrong source */,
57
+ role: ['admin', 'worker', 'tester'][idx % 3],
58
+ color: idx % 2 ? `#87f018` : `#180f87`,
59
+ rate: Math.round(Math.random() * 100),
60
+ dynamicType: ['text', 'email', 'checkbox', 'color', 'progress', 'barcode'][idx % 5],
61
+ dynamicValue: ['abcdefghijkl', 'heartyoh@hatiolab.com', 'true', 'orange', '50', '1234567890'][idx % 5],
62
+ homepage:
63
+ idx % 2 ? `http://hatiolab.com/${start + idx + 1}` : `http://deadpool.hatiolab.com/${start + idx + 1}`,
64
+ json5: {
65
+ abc: 'abc',
66
+ value: 123
67
+ },
68
+ createdAt: Date.now(),
69
+ updatedAt: Date.now()
70
+ }
71
+ })
72
+ }
73
+ }
74
+
75
+ const config = {
76
+ list: {
77
+ thumbnail: 'thumbnail',
78
+ fields: ['name', 'description'],
79
+ details: ['role', 'email']
80
+ },
81
+ columns: [
82
+ {
83
+ type: 'gutter',
84
+ gutterName: 'dirty',
85
+ fixed: true
86
+ },
87
+ {
88
+ type: 'gutter',
89
+ gutterName: 'sequence',
90
+ fixed: true
91
+ },
92
+ {
93
+ type: 'gutter',
94
+ gutterName: 'row-selector',
95
+ multiple: true,
96
+ fixed: true
97
+ },
98
+ {
99
+ type: 'gutter',
100
+ gutterName: 'button',
101
+ icon: 'edit',
102
+ title: 'edit',
103
+ handlers: {
104
+ click: function () {
105
+ console.log('clicked')
106
+ }
107
+ },
108
+ fixed: true
109
+ },
110
+ {
111
+ type: 'gutter',
112
+ gutterName: 'button',
113
+ icon: 'add',
114
+ title: 'add',
115
+ handlers: {
116
+ click: 'record-copy'
117
+ },
118
+ fixed: true
119
+ },
120
+ {
121
+ type: 'gutter',
122
+ gutterName: 'button',
123
+ icon: 'arrow_downward',
124
+ title: 'download',
125
+ handlers: {
126
+ click: 'move-down'
127
+ },
128
+ fixed: true
129
+ },
130
+ {
131
+ type: 'string',
132
+ name: 'id',
133
+ hidden: true
134
+ },
135
+ {
136
+ type: 'link',
137
+ name: 'name',
138
+ label: true,
139
+ header: 'name',
140
+ record: {
141
+ editable: true,
142
+ options: {
143
+ // href: 'http://hatiolab.com',
144
+ href: function (column: ColumnConfig, record: GristRecord, rowIndex: number) {
145
+ return record['homepage']
146
+ },
147
+ target: '_blank'
148
+ }
149
+ },
150
+ filter: 'search',
151
+ sortable: true,
152
+ width: 120,
153
+ fixed: true
154
+ },
155
+ {
156
+ type: 'string',
157
+ name: 'description',
158
+ header: 'description',
159
+ filter: 'search',
160
+ record: {
161
+ editable: true,
162
+ align: 'left'
163
+ },
164
+ width: 200,
165
+ handlers: {
166
+ click: (columns, data, column, record, rowIndex, target) => {
167
+ alert(`${column!.name} ${record![column!.name]}, row : ${rowIndex}`)
168
+ }
169
+ } as GristEventHandlerSet
170
+ },
171
+ {
172
+ type: 'email',
173
+ name: 'email',
174
+ label: true,
175
+ header: {
176
+ renderer: 'email',
177
+ group: 'information',
178
+ groupStyle: 'background-color: red;color: white',
179
+ style: 'background-color: red;color: white;'
180
+ },
181
+ record: {
182
+ editable: true
183
+ },
184
+ filter: 'search',
185
+ sortable: true,
186
+ width: 130,
187
+ validation: function (after, before, record, column) {
188
+ if (after.indexOf('@') == -1) {
189
+ document.dispatchEvent(
190
+ new CustomEvent('notify', {
191
+ detail: {
192
+ type: 'error',
193
+ message: `invalid value - ${after}`
194
+ }
195
+ })
196
+ )
197
+ return false
198
+ }
199
+ return true
200
+ } as ValidationCallback
201
+ },
202
+ {
203
+ type: 'boolean',
204
+ name: 'active',
205
+ header: {
206
+ renderer: 'active',
207
+ group: 'information'
208
+ },
209
+ record: {
210
+ editable: true
211
+ },
212
+ filter: true,
213
+ handlers: {
214
+ dblclick: () => {
215
+ const grist = document.querySelector('ox-grist') as any
216
+ console.log(grist!.dirtyRecords)
217
+ }
218
+ },
219
+ sortable: true,
220
+ width: 60
221
+ },
222
+ {
223
+ type: 'string[]',
224
+ name: 'role',
225
+ label: true,
226
+ header: {
227
+ renderer: 'role',
228
+ group: 'information'
229
+ },
230
+ record: {
231
+ options: ['', 'admin', 'worker', 'tester'],
232
+ editable: true
233
+ },
234
+ filter: true,
235
+ sortable: true,
236
+ width: 120
237
+ },
238
+ {
239
+ type: 'color',
240
+ name: 'color',
241
+ header: {
242
+ renderer: 'color',
243
+ group: 'information'
244
+ },
245
+ record: {
246
+ editable: true
247
+ },
248
+ sortable: true,
249
+ width: 50
250
+ },
251
+ {
252
+ type: 'float',
253
+ name: 'rate',
254
+ header: {
255
+ renderer: 'rate',
256
+ group: '2023',
257
+ groupStyle: 'background-color: blue;color: white;',
258
+ style: 'background-color: blue;color: white;'
259
+ },
260
+ record: {
261
+ align: 'right',
262
+ editable: true,
263
+ defaultValue: 10000.1
264
+ },
265
+ filter: 'between',
266
+ sortable: true,
267
+ width: 50
268
+ },
269
+ {
270
+ type: 'json5',
271
+ name: 'json5',
272
+ header: {
273
+ renderer: 'JSON5',
274
+ group: '2023'
275
+ },
276
+ width: 200
277
+ },
278
+ {
279
+ type: 'image',
280
+ name: 'thumbnail',
281
+ header: {
282
+ renderer: 'thumbnail',
283
+ group: '2023'
284
+ },
285
+ record: {
286
+ editable: true
287
+ },
288
+ width: 120
289
+ },
290
+ {
291
+ type: 'datetime',
292
+ name: 'updatedAt',
293
+ header: 'updated at',
294
+ record: {
295
+ editable: true,
296
+ defaultValue: {
297
+ name: 'now'
298
+ }
299
+ },
300
+ filter: 'between',
301
+ sortable: true,
302
+ width: 180
303
+ },
304
+ {
305
+ type: 'datetime',
306
+ name: 'createdAt',
307
+ header: 'created at',
308
+ record: {
309
+ editable: false
310
+ },
311
+ sortable: true,
312
+ width: 180
313
+ }
314
+ ],
315
+ rows: {
316
+ selectable: {
317
+ multiple: true
318
+ },
319
+ handlers: {
320
+ focus: 'select-row-toggle'
321
+ },
322
+ classifier: function (record, rowIndex) {
323
+ const rate = record['rate']
324
+ const emphasized =
325
+ rate < 10 ? ['black', 'white'] : rate < 25 ? ['yellow', 'blue'] : rate < 40 ? ['cyan', 'red'] : undefined
326
+ return {
327
+ emphasized
328
+ }
329
+ } as GristClassifier
330
+ },
331
+ sorters: [
332
+ {
333
+ name: 'name',
334
+ desc: true
335
+ },
336
+ {
337
+ name: 'email'
338
+ }
339
+ ],
340
+ pagination: {
341
+ pages: [20, 30, 50, 100, 200]
342
+ }
343
+ }
344
+
345
+ export default {
346
+ title: 'group header',
347
+ component: 'ox-grist',
348
+ argTypes: {
349
+ config: { control: 'object' }
350
+ }
351
+ }
352
+
353
+ interface Story<T> {
354
+ (args: T): TemplateResult
355
+ args?: Partial<T>
356
+ argTypes?: Record<string, unknown>
357
+ }
358
+
359
+ interface ArgTypes {
360
+ config: object
361
+ }
362
+
363
+ const Template: Story<ArgTypes> = ({ config }: ArgTypes) => html` <link
364
+ href="https://fonts.googleapis.com/css?family=Material+Icons&display=block"
365
+ rel="stylesheet"
366
+ />
367
+ <link href="/themes/app-theme.css" rel="stylesheet" />
368
+ <link href="/themes/oops-theme.css" rel="stylesheet" />
369
+ <link href="/themes/grist-theme.css" rel="stylesheet" />
370
+
371
+ <style>
372
+ [slot='headroom'] {
373
+ display: flex;
374
+ flex-direction: row;
375
+ align-items: center;
376
+ padding: var(--padding-default) var(--padding-wide);
377
+ background-color: var(--theme-white-color);
378
+ box-shadow: var(--box-shadow);
379
+
380
+ --mdc-icon-size: 24px;
381
+ }
382
+ #sorters mwc-icon,
383
+ #modes mwc-icon {
384
+ --mdc-icon-size: 18px;
385
+ }
386
+ #sorters {
387
+ margin-left: auto;
388
+ margin-right: var(--margin-default);
389
+ padding-left: var(--padding-narrow);
390
+ border-bottom: var(--border-dark-color);
391
+ position: relative;
392
+ color: var(--secondary-color);
393
+ font-size: var(--fontsize-default);
394
+ user-select: none;
395
+ }
396
+
397
+ #sorters > * {
398
+ padding: var(--padding-narrow);
399
+ vertical-align: middle;
400
+ }
401
+
402
+ #modes > * {
403
+ padding: var(--padding-narrow);
404
+ opacity: 0.5;
405
+ color: var(--primary-text-color);
406
+ cursor: pointer;
407
+ }
408
+
409
+ #modes > mwc-icon[active] {
410
+ border-radius: 9px;
411
+ background-color: rgba(var(--primary-color-rgb), 0.05);
412
+ opacity: 1;
413
+ color: var(--secondary-text-color);
414
+ cursor: default;
415
+ }
416
+
417
+ #modes > mwc-icon:hover {
418
+ opacity: 1;
419
+ color: var(--secondary-text-color);
420
+ }
421
+
422
+ #add {
423
+ width: 50px;
424
+ text-align: right;
425
+ }
426
+
427
+ #add button {
428
+ background-color: var(--primary-color);
429
+ border: 0;
430
+ border-radius: 50%;
431
+ padding: 5px;
432
+ width: 36px;
433
+ height: 36px;
434
+ cursor: pointer;
435
+ }
436
+
437
+ #add button:hover {
438
+ background-color: var(--focus-background-color);
439
+ box-shadow: var(--box-shadow);
440
+ }
441
+
442
+ #add button mwc-icon {
443
+ font-size: 2em;
444
+ color: var(--theme-white-color);
445
+ }
446
+
447
+ #filters {
448
+ display: flex;
449
+ justify-content: center;
450
+ align-items: center;
451
+ }
452
+
453
+ #filters * {
454
+ margin-right: var(--margin-default);
455
+ }
456
+
457
+ @media only screen and (max-width: 460px) {
458
+ #filters {
459
+ flex-direction: column;
460
+ }
461
+
462
+ #modes {
463
+ display: none;
464
+ }
465
+ }
466
+ </style>
467
+
468
+ <ox-grist
469
+ mode="GRID"
470
+ .config=${config}
471
+ .fetchHandler=${fetchHandler}
472
+ @filters-change=${(e: Event) => console.log('filters', (e.target as any).filters)}
473
+ >
474
+ <div slot="headroom">
475
+ <div id="filters">
476
+ <ox-filters-form autofocus></ox-filters-form>
477
+ </div>
478
+
479
+ <div id="sorters">
480
+ Sort
481
+ <mwc-icon
482
+ @click=${(e: Event) => {
483
+ const target = e.currentTarget as HTMLElement
484
+ ;(target.closest('#sorters')!.querySelector('#sorter-control') as any).open({
485
+ right: 0,
486
+ top: target.offsetTop + target.offsetHeight
487
+ })
488
+ }}
489
+ >expand_more</mwc-icon
490
+ >
491
+ <ox-popup id="sorter-control">
492
+ <ox-sorters-control> </ox-sorters-control>
493
+ </ox-popup>
494
+ </div>
495
+
496
+ <ox-record-creator id="add" light-popup>
497
+ <button><mwc-icon>add</mwc-icon></button>
498
+ </ox-record-creator>
499
+ </div>
500
+ </ox-grist>`
501
+
502
+ export const Regular = Template.bind({})
503
+ Regular.args = {
504
+ config
505
+ }