@operato/data-grist 0.3.18 → 0.3.22

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.
@@ -44,11 +44,15 @@
44
44
  <link href="/themes/oops-theme.css" rel="stylesheet" />
45
45
  <link href="/themes/grist-theme.css" rel="stylesheet" />
46
46
  </head>
47
+
47
48
  <body>
48
49
  <script type="module">
49
50
  import { LitElement, html, css, render } from 'lit'
50
51
  import '../dist/index.js'
51
- import '@operato/popup'
52
+ import '../dist/src/filters/filters-form.js'
53
+ import '../dist/src/sorters/sorters-control.js'
54
+ import '../dist/src/record-view/record-creator.js'
55
+ import '@operato/popup/ox-popup-list.js'
52
56
  import '@material/mwc-icon'
53
57
 
54
58
  const fetchHandler = async ({ page, limit, sorters = [] }) => {
@@ -65,7 +69,8 @@
65
69
  return {
66
70
  id: idx,
67
71
  name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
68
- description: idx % 2 ? `hatiolab manager-${start + idx + 1}` : `hatiosea manager-${start + idx + 1}`,
72
+ description:
73
+ idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
69
74
  email: idx % 2 ? `shnam-${start + idx + 1}@gmail.com` : `heartyoh-${start + idx + 1}@gmail.com`,
70
75
  active: Math.round(Math.random() * 2) % 2 ? true : false,
71
76
  barcode: idx % 2 ? `1234567890${start + idx + 1}` : `0987654321${start + idx + 1}`,
@@ -81,10 +86,14 @@
81
86
  name: 'HatioSEA',
82
87
  description: `말레이시아 세티아알람-${start + idx + 1}`
83
88
  },
84
- image:
85
- idx % 2
89
+ thumbnail:
90
+ idx % 4 === 0
91
+ ? '' /* no source */
92
+ : idx % 4 === 1
86
93
  ? `http://www.hatiolab.com/assets/img/operato-biz3.png`
87
- : `http://www.hatiolab.com/assets/img/thingsboard-30.png`,
94
+ : idx % 4 === 2
95
+ ? `http://www.hatiolab.com/assets/img/thingsboard-30.png`
96
+ : `http://www.hatiolab.com/wrong-url.png` /* wrong source */,
88
97
  role: ['admin', 'worker', 'tester'][idx % 3],
89
98
  color: idx % 2 ? `#87f018` : `#180f87`,
90
99
  rate: Math.round(Math.random() * 100),
@@ -107,9 +116,7 @@
107
116
 
108
117
  const config = {
109
118
  list: {
110
- thumbnail: function (record, rowIndex) {
111
- return html` <img src=${record.image} style="width: 100%; height: 100%;" /> `
112
- },
119
+ thumbnail: 'thumbnail',
113
120
  fields: ['name', 'description'],
114
121
  details: ['role', 'email']
115
122
  },
@@ -153,10 +160,11 @@
153
160
  // href: 'http://hatiolab.com',
154
161
  href: function (column, record, rowIndex) {
155
162
  return record['homepage']
156
- }
157
- // target: '_blank'
163
+ },
164
+ target: '_blank'
158
165
  }
159
166
  },
167
+ filter: 'search',
160
168
  sortable: true,
161
169
  width: 120
162
170
  },
@@ -164,13 +172,14 @@
164
172
  type: 'string',
165
173
  name: 'description',
166
174
  header: 'description',
175
+ filter: 'search',
167
176
  record: {
168
177
  editable: true,
169
178
  align: 'left'
170
179
  },
171
180
  width: 200,
172
181
  handlers: {
173
- dblclick: (columns, data, column, record, rowIndex) => {
182
+ click: (columns, data, column, record, rowIndex, target) => {
174
183
  alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`)
175
184
  }
176
185
  }
@@ -183,6 +192,7 @@
183
192
  record: {
184
193
  editable: true
185
194
  },
195
+ filter: 'search',
186
196
  sortable: true,
187
197
  width: 130,
188
198
  validation: function (after, before, record, column) {
@@ -207,6 +217,7 @@
207
217
  record: {
208
218
  editable: true
209
219
  },
220
+ filter: true,
210
221
  handlers: {
211
222
  dblclick: () => {
212
223
  const grist = document.querySelector('ox-grist')
@@ -225,6 +236,10 @@
225
236
  options: ['admin', 'worker', 'tester'],
226
237
  editable: true
227
238
  },
239
+ filter: {
240
+ options: ['admin', 'worker', 'tester', 'xyz', 'VERY'],
241
+ multiple: true /* this case, operator should be 'in' */
242
+ },
228
243
  sortable: true,
229
244
  width: 120
230
245
  },
@@ -246,6 +261,7 @@
246
261
  align: 'right',
247
262
  editable: true
248
263
  },
264
+ filter: 'between',
249
265
  sortable: true,
250
266
  width: 50
251
267
  },
@@ -255,6 +271,14 @@
255
271
  header: 'JSON5',
256
272
  width: 200
257
273
  },
274
+ {
275
+ type: 'image',
276
+ name: 'thumbnail',
277
+ header: 'thumbnail',
278
+ record: {
279
+ editable: true
280
+ }
281
+ },
258
282
  {
259
283
  type: 'datetime',
260
284
  name: 'updatedAt',
@@ -262,6 +286,7 @@
262
286
  record: {
263
287
  editable: true
264
288
  },
289
+ filter: 'between',
265
290
  sortable: true,
266
291
  width: 180
267
292
  },
@@ -270,7 +295,7 @@
270
295
  name: 'createdAt',
271
296
  header: 'created at',
272
297
  record: {
273
- editable: true
298
+ editable: false
274
299
  },
275
300
  sortable: true,
276
301
  width: 180
@@ -311,6 +336,7 @@
311
336
  css`
312
337
  :host {
313
338
  display: flex;
339
+ flex-direction: column;
314
340
  }
315
341
 
316
342
  ox-grist {
@@ -321,34 +347,95 @@
321
347
  --grid-record-emphasized-color: yellow;
322
348
  }
323
349
 
324
- #headroom {
350
+ [slot='headroom'] {
325
351
  display: flex;
326
- flex-direction: column;
327
- background-color: var(--primary-color);
328
- height: 200px;
352
+ flex-direction: row;
329
353
  align-items: center;
330
- justify-content: center;
331
- color: var(--theme-white-color);
354
+ padding: var(--padding-default) var(--padding-wide);
355
+ border-top: 2px solid rgba(0, 0, 0, 0.2);
356
+ background-color: var(--theme-white-color);
357
+ box-shadow: var(--box-shadow);
358
+
359
+ --mdc-icon-size: 24px;
360
+ }
361
+
362
+ #sorters {
363
+ margin-left: auto;
364
+ position: relative;
365
+ }
366
+
367
+ #sorters > * {
368
+ padding: var(--padding-narrow);
369
+ margin-right: var(--margin-default);
332
370
  }
333
371
 
334
372
  #modes > * {
335
373
  padding: var(--padding-narrow);
336
- font-size: 1.5em;
337
- opacity: 0.7;
374
+ opacity: 0.5;
375
+ color: var(--primary-text-color);
376
+ cursor: pointer;
338
377
  }
339
378
 
340
379
  #modes > mwc-icon[active] {
341
- border: 1px solid var(--status-warning-color);
342
380
  border-radius: 9px;
343
- background-color: rgba(0, 0, 0, 0.3);
381
+ background-color: rgba(var(--primary-color-rgb), 0.05);
344
382
  opacity: 1;
383
+ color: var(--secondary-text-color);
384
+ cursor: default;
345
385
  }
346
386
 
347
- #filters {
348
- position: absolute;
349
- left: 10px;
350
- bottom: 10px;
351
- width: calc(100% - 20px);
387
+ #modes > mwc-icon:hover {
388
+ opacity: 1;
389
+ color: var(--secondary-text-color);
390
+ }
391
+
392
+ #add {
393
+ width: 50px;
394
+ text-align: right;
395
+ }
396
+
397
+ #add button {
398
+ background-color: var(--status-success-color);
399
+ border: 0;
400
+ border-radius: 50%;
401
+ padding: 5px;
402
+ width: 36px;
403
+ height: 36px;
404
+ cursor: pointer;
405
+ }
406
+
407
+ #add button:hover {
408
+ background-color: var(--focus-background-color);
409
+ box-shadow: var(--box-shadow);
410
+ }
411
+
412
+ #add button mwc-icon {
413
+ font-size: 2em;
414
+ color: var(--theme-white-color);
415
+ }
416
+
417
+ #filters * {
418
+ margin-right: var(--margin-default);
419
+ }
420
+
421
+ #tailer {
422
+ display: flex;
423
+ flex-direction: row;
424
+ margin: 0 var(--margin-default);
425
+ }
426
+
427
+ #tailer a {
428
+ padding: 0 var(--padding-narrow) 0 var(--padding-default);
429
+ margin: 0 var(--margin-narrow);
430
+ border-left: 1px solid rgba(0, 0, 0, 0.1);
431
+ font-size: var(--fontsize-default);
432
+ color: var(--primary-color);
433
+ }
434
+
435
+ @media only screen and (max-width: 460px) {
436
+ #modes {
437
+ display: none;
438
+ }
352
439
  }
353
440
  `
354
441
  ]
@@ -359,27 +446,49 @@
359
446
  }
360
447
  }
361
448
 
449
+ get searchForm() {
450
+ return this.shadowRoot.querySelector('ox-filters-form')
451
+ }
452
+
362
453
  render() {
363
454
  const mode = this.mode || 'CARD'
364
455
 
365
456
  return html`
366
457
  <ox-grist .config=${config} .mode=${mode} auto-fetch .fetchHandler=${fetchHandler}>
458
+ <ox-filters-form slot="headroom" @change=${e => console.log('changed', e.detail)}></ox-filters-form>
459
+
367
460
  <div slot="headroom" id="headroom">
368
- <h1>HEAD ROOM AREA</h1>
461
+ <div id="sorters">
462
+ <mwc-icon
463
+ @click=${e => {
464
+ const target = e.currentTarget
465
+ this.renderRoot.querySelector('#sorter-control').open({
466
+ right: 0,
467
+ top: target.offsetTop + target.offsetHeight
468
+ })
469
+ }}
470
+ >sort</mwc-icon
471
+ >
472
+ <ox-popup id="sorter-control">
473
+ <ox-sorters-control> </ox-sorters-control>
474
+ </ox-popup>
475
+ </div>
476
+
369
477
  <div id="modes">
370
478
  <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>view_list</mwc-icon>
371
479
  <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>menu</mwc-icon>
372
480
  <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
373
481
  </div>
482
+
374
483
  <div id="tailer">
375
- <a href="./report-test.html">Report Test</a>|
484
+ <a href="./report-test.html">Report Test</a>
376
485
  <a
377
486
  href="#"
378
487
  @click=${() => {
379
488
  this.renderRoot.querySelector('ox-grist').reset()
380
489
  }}
381
490
  >Reset</a
382
- >|
491
+ >
383
492
  <a
384
493
  href="#"
385
494
  @click=${() => {
@@ -389,61 +498,9 @@
389
498
  >
390
499
  </div>
391
500
 
392
- <div id="filters">
393
- <mwc-icon
394
- @click=${e => {
395
- const target = e.currentTarget
396
- this.renderRoot.querySelector('ox-popup-list').open({
397
- left: target.offsetLeft,
398
- top: target.offsetTop + target.offsetHeight
399
- })
400
- }}
401
- >sort</mwc-icon
402
- >
403
- <mwc-icon
404
- @click=${e => {
405
- const target = e.currentTarget
406
- this.renderRoot.querySelector('ox-popup-list').open({
407
- left: target.offsetLeft,
408
- top: target.offsetTop + target.offsetHeight
409
- })
410
- }}
411
- >more_horiz</mwc-icon
412
- >
413
- <mwc-icon
414
- @click=${e => {
415
- const target = e.currentTarget
416
- this.renderRoot.querySelector('ox-popup-list').open({
417
- left: target.offsetLeft,
418
- top: target.offsetTop + target.offsetHeight
419
- })
420
- }}
421
- >sort</mwc-icon
422
- >
423
-
424
- <ox-popup-list @select=${() => console.log(e.detail)} multiple>
425
- <div
426
- option
427
- @click=${function (e) {
428
- const icon = e.currentTarget.querySelector('mwc-icon')
429
- icon.innerHTML = icon.innerHTML == 'check' ? '' : 'check'
430
- }}
431
- >
432
- <mwc-icon slot="icon" style="width: 20px;height: 20px;"></mwc-icon>
433
- <span>click me to toggle</span>
434
- </div>
435
- <div
436
- option
437
- @click=${function (e) {
438
- const icon = e.currentTarget.querySelector('mwc-icon')
439
- icon.innerHTML = icon.innerHTML == 'check' ? '' : 'check'
440
- }}
441
- >
442
- <mwc-icon slot="icon" style="width: 20px;height: 20px;"></mwc-icon>
443
- <span>click me to toggle</span>
444
- </div>
445
- </ox-popup-list>
446
- </div>
501
+ <ox-record-creator id="add" light-popup>
502
+ <button><mwc-icon>add</mwc-icon></button>
503
+ </ox-record-creator>
447
504
  </div>
448
505
  </ox-grist>
449
506
  `
package/demo/index.html CHANGED
@@ -353,12 +353,24 @@
353
353
  align-items: center;
354
354
  padding: var(--padding-default) var(--padding-wide);
355
355
  border-top: 2px solid rgba(0, 0, 0, 0.2);
356
- background-color: var(--main-section-background-color);
356
+ background-color: var(--theme-white-color);
357
+ box-shadow: var(--box-shadow);
358
+
359
+ --mdc-icon-size: 24px;
360
+ }
361
+
362
+ #sorters {
363
+ margin-left: auto;
364
+ position: relative;
365
+ }
366
+
367
+ #sorters > * {
368
+ padding: var(--padding-narrow);
369
+ margin-right: var(--margin-default);
357
370
  }
358
371
 
359
372
  #modes > * {
360
373
  padding: var(--padding-narrow);
361
- font-size: 1em;
362
374
  opacity: 0.5;
363
375
  color: var(--primary-text-color);
364
376
  cursor: pointer;
@@ -372,41 +384,38 @@
372
384
  cursor: default;
373
385
  }
374
386
 
375
- #filters {
376
- display: flex;
377
- flex-direction: row;
378
- justify-content: space-between;
379
- margin-right: auto;
380
- align-items: center;
387
+ #modes > mwc-icon:hover {
388
+ opacity: 1;
389
+ color: var(--secondary-text-color);
381
390
  }
382
391
 
383
- #filters > * {
384
- padding: var(--padding-default) var(--padding-wide);
392
+ #add {
393
+ width: 50px;
394
+ text-align: right;
385
395
  }
386
396
 
387
- #search {
388
- flex: 1;
389
-
390
- display: flex;
391
- position: relative;
392
- align-items: center;
397
+ #add button {
398
+ background-color: var(--status-success-color);
399
+ border: 0;
400
+ border-radius: 50%;
401
+ padding: 5px;
402
+ width: 36px;
403
+ height: 36px;
404
+ cursor: pointer;
405
+ }
393
406
 
394
- --mdc-icon-size: 20px;
407
+ #add button:hover {
408
+ background-color: var(--focus-background-color);
409
+ box-shadow: var(--box-shadow);
395
410
  }
396
411
 
397
- #search [type='text'] {
398
- flex: 1;
399
- background-color: transparent;
400
- border: 0;
401
- border-bottom: var(--border-dark-color);
402
- padding: var(--padding-narrow) var(--padding-narrow) 7px 25px;
403
- font-size: var(--fontsize-large);
404
- outline: none;
412
+ #add button mwc-icon {
413
+ font-size: 2em;
414
+ color: var(--theme-white-color);
405
415
  }
406
416
 
407
- #search mwc-icon {
408
- position: absolute;
409
- color: var(--secondary-color);
417
+ #filters * {
418
+ margin-right: var(--margin-default);
410
419
  }
411
420
 
412
421
  #tailer {
@@ -423,29 +432,9 @@
423
432
  color: var(--primary-color);
424
433
  }
425
434
 
426
- #add button {
427
- background-color: var(--status-success-color);
428
- border: 0;
429
- border-radius: 50%;
430
- padding: 5px;
431
- width: 36px;
432
- height: 36px;
433
- cursor: pointer;
434
- }
435
-
436
- #add button:hover {
437
- background-color: var(--focus-background-color);
438
- box-shadow: var(--box-shadow);
439
- }
440
-
441
- #add button mwc-icon {
442
- font-size: 2em;
443
- color: var(--theme-white-color);
444
- }
445
-
446
435
  @media only screen and (max-width: 460px) {
447
- #filters {
448
- flex-direction: column;
436
+ #modes {
437
+ display: none;
449
438
  }
450
439
  }
451
440
  `
@@ -466,31 +455,25 @@
466
455
 
467
456
  return html`
468
457
  <ox-grist .config=${config} .mode=${mode} auto-fetch .fetchHandler=${fetchHandler}>
469
- <ox-filters-form slot="headroom" @change=${e => console.log(e.detail)}></ox-filters-form>
458
+ <ox-filters-form slot="headroom" @change=${e => console.log('changed', e.detail)}></ox-filters-form>
470
459
 
471
460
  <div slot="headroom" id="headroom">
472
- <div id="filters">
473
- <div id="search">
474
- <mwc-icon>search</mwc-icon>
475
- <input type="text" />
476
- </div>
477
-
478
- <div>
479
- <mwc-icon
480
- @click=${e => {
481
- const target = e.currentTarget
482
- this.renderRoot.querySelector('#sorter-control').open({
483
- left: target.offsetLeft,
484
- top: target.offsetTop + target.offsetHeight
485
- })
486
- }}
487
- >sort</mwc-icon
488
- >
489
- <ox-popup id="sorter-control">
490
- <ox-sorters-control> </ox-sorters-control>
491
- </ox-popup>
492
- </div>
461
+ <div id="sorters">
462
+ <mwc-icon
463
+ @click=${e => {
464
+ const target = e.currentTarget
465
+ this.renderRoot.querySelector('#sorter-control').open({
466
+ right: 0,
467
+ top: target.offsetTop + target.offsetHeight
468
+ })
469
+ }}
470
+ >sort</mwc-icon
471
+ >
472
+ <ox-popup id="sorter-control">
473
+ <ox-sorters-control> </ox-sorters-control>
474
+ </ox-popup>
493
475
  </div>
476
+
494
477
  <div id="modes">
495
478
  <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>view_list</mwc-icon>
496
479
  <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>menu</mwc-icon>
@@ -40,7 +40,9 @@ let DataGridHeader = class DataGridHeader extends LitElement {
40
40
  </span>
41
41
  `
42
42
  : undefined}
43
- ${column.filter ? html ` <span filter> ${this._renderFilterHeader(column)} </span> ` : undefined}
43
+ ${column.filter && column.filter.operator !== 'search'
44
+ ? html ` <span filter> ${this._renderFilterHeader(column)} </span> `
45
+ : undefined}
44
46
  ${column.resizable !== false
45
47
  ? html `
46
48
  <span splitter draggable="false" @mousedown=${(e) => this._mousedown(e, idx)}
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid-header.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-header.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-popup.js'\nimport '@material/mwc-icon'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport throttle from 'lodash-es/throttle'\n\nimport { OxPopup } from '@operato/popup'\nimport { closestElement } from '@operato/utils'\n\nimport { ZERO_COLUMNS, ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'\nimport { FilterStyles } from '../filters/filter-styles'\nimport { getFilterRenderer } from '../filters/registry'\nimport { ColumnConfig, FilterConfigObject, GristConfig, GristData, SortersConfig } from '../types'\n\n@customElement('ox-grid-header')\nexport class DataGridHeader extends LitElement {\n static styles = [\n FilterStyles,\n css`\n :host {\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n\n overflow: hidden;\n }\n\n div[column] {\n display: flex;\n\n white-space: nowrap;\n overflow: hidden;\n background-color: var(--grid-header-background-color);\n border-top: var(--grid-header-top-border);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n color: var(--grid-header-color);\n }\n\n div[gutter] {\n padding: var(--padding-default) 0 var(--padding-narrow) 0;\n text-align: center;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n }\n\n span[for-title] {\n flex: 1;\n text-overflow: ellipsis;\n line-height: 1.6;\n text-transform: capitalize;\n }\n span[for-title] mwc-icon {\n font-size: var(--grid-record-fontsize);\n }\n\n span[sorter],\n span[filter] {\n padding: 0;\n border: 0;\n }\n span[sorter] mwc-icon {\n font-size: var(--grid-header-sorter-size);\n }\n\n span[filter] > mwc-icon {\n font-size: var(--fontsize-default);\n line-height: 20px;\n }\n\n span[splitter] {\n cursor: col-resize;\n border-right: var(--grid-header-splitter-border);\n }\n span[splitter]:hover {\n border-right: var(--grid-header-splitter-border-hover);\n }\n input[type='checkbox'],\n input[type='radio'] {\n margin: 3px 0 0 0;\n zoom: var(--grist-input-zoom);\n }\n [filter-title] {\n color: var(--grid-header-filter-title-color);\n font: var(--grid-header-filter-title-font);\n text-transform: capitalize;\n }\n [filter-title] * {\n vertical-align: middle;\n }\n [filter-title] mwc-icon {\n opacity: 0.7;\n color: var(--grid-header-filter-title-icon-color);\n }\n [filter] input[type='checkbox'] {\n margin-left: 10px;\n margin-bottom: 5px;\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n }\n `\n ]\n\n @property({ type: Object }) config: GristConfig = ZERO_CONFIG\n @property({ type: Array }) columns: ColumnConfig[] = ZERO_COLUMNS\n @property({ type: Object }) data: GristData = ZERO_DATA\n\n @state() private _sorters: SortersConfig = []\n private _lastAccVal?: number\n private _throttledNotifier?: any\n\n connectedCallback() {\n super.connectedCallback()\n\n const grid = closestElement('ox-grist', this)\n grid?.addEventListener('sorters-change', (e: Event) => {\n this._sorters = (e as CustomEvent).detail\n })\n }\n\n render() {\n var columns = this.columns || []\n\n return html`\n ${columns.map((column, idx) =>\n !column.hidden\n ? html`\n <div ?gutter=${column.type == 'gutter'} column>\n <span for-title @click=${(e: MouseEvent) => this._changeSort(column)}\n >${this._renderHeader(column)}\n </span>\n\n ${column.sortable\n ? html`\n <span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>\n ${this._renderSortHeader(column)}\n </span>\n `\n : undefined}\n ${column.filter ? html` <span filter> ${this._renderFilterHeader(column)} </span> ` : undefined}\n ${column.resizable !== false\n ? html`\n <span splitter draggable=\"false\" @mousedown=${(e: MouseEvent) => this._mousedown(e, idx)}\n >&nbsp;</span\n >\n `\n : undefined}\n </div>\n `\n : undefined\n )}\n\n <div column></div>\n `\n }\n\n _renderHeader(column: ColumnConfig) {\n var { renderer } = column.header || {}\n var title = renderer.call(this, column)\n\n return html` ${title} `\n }\n\n _renderSortHeader(column: ColumnConfig) {\n var sorters = this._sorters\n\n var sorter = sorters.find(sorter => column.type !== 'gutter' && column.name == sorter.name)\n if (!sorter) {\n return html``\n }\n\n if (sorters.length > 1) {\n var rank = sorters.indexOf(sorter) + 1\n return sorter.desc\n ? html` <mwc-icon>keyboard_arrow_up</mwc-icon><sub>${rank}</sub> `\n : html` <mwc-icon>keyboard_arrow_down</mwc-icon><sub>${rank}</sub> `\n } else {\n return sorter.desc\n ? html` <mwc-icon>keyboard_arrow_up</mwc-icon> `\n : html` <mwc-icon>keyboard_arrow_down</mwc-icon> `\n }\n }\n\n _renderFilterHeader(column: ColumnConfig) {\n var filter = column.filter as FilterConfigObject\n const type = filter.type\n const idx = filter!.operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(type)[idx]\n\n return html`\n <mwc-icon\n @click=${(e: Event) => {\n const parent = (e.target as HTMLElement).closest('[column]') as HTMLElement\n const popup = parent.querySelector('ox-popup, ox-popup-list') as OxPopup | null\n // const popup = (e.target as HTMLElement).nextSibling as OxPopupList | null\n\n // absolute position인 popup의 위치 부모는 grist 이므로,\n // data-grid-header 의 포지션 부모(grist)의 위치로부터 계산해야함.\n // this의 position을 relative로 하지 못하는 이유 : ox-popup-list가 grid body에 덮히기 때문.\n const top = parent.offsetTop + parent.offsetHeight\n const right = this.clientWidth - (parent.offsetLeft + parent.offsetWidth - this.scrollLeft)\n\n popup?.open({\n right,\n top\n })\n }}\n >filter_alt</mwc-icon\n >\n\n ${!renderer\n ? html``\n : type === 'select'\n ? html`<ox-popup-list multiple attr-selected=\"checked\" with-search\n ><div filter-title slot=\"header\">\n <mwc-icon>filter_alt</mwc-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, this)}</ox-popup-list\n >`\n : html` <ox-popup\n ><div filter-title><mwc-icon>filter_alt</mwc-icon> filter by <strong>${column.name}</strong></div>\n ${renderer(column, this)}</ox-popup\n >`}\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('config')) {\n this._sorters = this.config.sorters || []\n }\n }\n\n _changeSort(column: ColumnConfig) {\n if (!column.sortable) {\n return\n }\n\n var sorters = [...this._sorters]\n\n var idx = sorters.findIndex(sorter => sorter.name == column.name)\n if (idx !== -1) {\n let sorter = sorters[idx]\n if (sorter.desc) {\n sorters.splice(idx, 1)\n } else {\n sorter.desc = true\n }\n } else {\n var sorter = {\n name: column.name\n }\n\n sorters.push(sorter)\n }\n\n this._sorters = sorters\n\n this.dispatchEvent(\n new CustomEvent('sorters-change', {\n bubbles: true,\n composed: true,\n detail: this._sorters\n })\n )\n }\n\n _accumalate(x: number) {\n this._lastAccVal = (this._lastAccVal ?? 0) + x\n return this._lastAccVal\n }\n\n _notifyWidthChange(idx: number, width: number) {\n if (!this._throttledNotifier) {\n this._throttledNotifier = throttle((idx: number, width: number) => {\n this.dispatchEvent(\n new CustomEvent('column-width-change', {\n bubbles: true,\n composed: true,\n detail: {\n idx,\n width\n }\n })\n )\n\n this._lastAccVal = 0\n }, 100)\n }\n\n this._throttledNotifier(idx, width)\n }\n\n _mousedown(e: MouseEvent, idx: number) {\n e.stopPropagation()\n e.preventDefault()\n\n var mousemoveHandler = ((e: MouseEvent) => {\n e.stopPropagation()\n e.preventDefault()\n let column = this.columns[idx]\n\n let width = Math.max(0, Number(column.width) + this._accumalate(e.movementX))\n if (width == 0) {\n /* CLARIFY-ME 왜 마지막 이벤트의 offsetX로 음수 값이 오는가 */\n return\n }\n\n this._notifyWidthChange(idx, width)\n }).bind(this)\n\n var mouseupHandler = ((e: MouseEvent) => {\n document.removeEventListener('mousemove', mousemoveHandler)\n document.removeEventListener('mouseup', mouseupHandler)\n\n mousemoveHandler(e)\n }).bind(this)\n\n document.addEventListener('mousemove', mousemoveHandler)\n document.addEventListener('mouseup', mouseupHandler)\n }\n}\n"]}
1
+ {"version":3,"file":"data-grid-header.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-header.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-popup.js'\nimport '@material/mwc-icon'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport throttle from 'lodash-es/throttle'\n\nimport { OxPopup } from '@operato/popup'\nimport { closestElement } from '@operato/utils'\n\nimport { ZERO_COLUMNS, ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'\nimport { FilterStyles } from '../filters/filter-styles'\nimport { getFilterRenderer } from '../filters/registry'\nimport { ColumnConfig, FilterConfigObject, GristConfig, GristData, SortersConfig } from '../types'\n\n@customElement('ox-grid-header')\nexport class DataGridHeader extends LitElement {\n static styles = [\n FilterStyles,\n css`\n :host {\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n\n overflow: hidden;\n }\n\n div[column] {\n display: flex;\n\n white-space: nowrap;\n overflow: hidden;\n background-color: var(--grid-header-background-color);\n border-top: var(--grid-header-top-border);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n color: var(--grid-header-color);\n }\n\n div[gutter] {\n padding: var(--padding-default) 0 var(--padding-narrow) 0;\n text-align: center;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n }\n\n span[for-title] {\n flex: 1;\n text-overflow: ellipsis;\n line-height: 1.6;\n text-transform: capitalize;\n }\n span[for-title] mwc-icon {\n font-size: var(--grid-record-fontsize);\n }\n\n span[sorter],\n span[filter] {\n padding: 0;\n border: 0;\n }\n span[sorter] mwc-icon {\n font-size: var(--grid-header-sorter-size);\n }\n\n span[filter] > mwc-icon {\n font-size: var(--fontsize-default);\n line-height: 20px;\n }\n\n span[splitter] {\n cursor: col-resize;\n border-right: var(--grid-header-splitter-border);\n }\n span[splitter]:hover {\n border-right: var(--grid-header-splitter-border-hover);\n }\n input[type='checkbox'],\n input[type='radio'] {\n margin: 3px 0 0 0;\n zoom: var(--grist-input-zoom);\n }\n [filter-title] {\n color: var(--grid-header-filter-title-color);\n font: var(--grid-header-filter-title-font);\n text-transform: capitalize;\n }\n [filter-title] * {\n vertical-align: middle;\n }\n [filter-title] mwc-icon {\n opacity: 0.7;\n color: var(--grid-header-filter-title-icon-color);\n }\n [filter] input[type='checkbox'] {\n margin-left: 10px;\n margin-bottom: 5px;\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n }\n `\n ]\n\n @property({ type: Object }) config: GristConfig = ZERO_CONFIG\n @property({ type: Array }) columns: ColumnConfig[] = ZERO_COLUMNS\n @property({ type: Object }) data: GristData = ZERO_DATA\n\n @state() private _sorters: SortersConfig = []\n private _lastAccVal?: number\n private _throttledNotifier?: any\n\n connectedCallback() {\n super.connectedCallback()\n\n const grid = closestElement('ox-grist', this)\n grid?.addEventListener('sorters-change', (e: Event) => {\n this._sorters = (e as CustomEvent).detail\n })\n }\n\n render() {\n var columns = this.columns || []\n\n return html`\n ${columns.map((column, idx) =>\n !column.hidden\n ? html`\n <div ?gutter=${column.type == 'gutter'} column>\n <span for-title @click=${(e: MouseEvent) => this._changeSort(column)}\n >${this._renderHeader(column)}\n </span>\n\n ${column.sortable\n ? html`\n <span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>\n ${this._renderSortHeader(column)}\n </span>\n `\n : undefined}\n ${column.filter && (column.filter as FilterConfigObject).operator !== 'search'\n ? html` <span filter> ${this._renderFilterHeader(column)} </span> `\n : undefined}\n ${column.resizable !== false\n ? html`\n <span splitter draggable=\"false\" @mousedown=${(e: MouseEvent) => this._mousedown(e, idx)}\n >&nbsp;</span\n >\n `\n : undefined}\n </div>\n `\n : undefined\n )}\n\n <div column></div>\n `\n }\n\n _renderHeader(column: ColumnConfig) {\n var { renderer } = column.header || {}\n var title = renderer.call(this, column)\n\n return html` ${title} `\n }\n\n _renderSortHeader(column: ColumnConfig) {\n var sorters = this._sorters\n\n var sorter = sorters.find(sorter => column.type !== 'gutter' && column.name == sorter.name)\n if (!sorter) {\n return html``\n }\n\n if (sorters.length > 1) {\n var rank = sorters.indexOf(sorter) + 1\n return sorter.desc\n ? html` <mwc-icon>keyboard_arrow_up</mwc-icon><sub>${rank}</sub> `\n : html` <mwc-icon>keyboard_arrow_down</mwc-icon><sub>${rank}</sub> `\n } else {\n return sorter.desc\n ? html` <mwc-icon>keyboard_arrow_up</mwc-icon> `\n : html` <mwc-icon>keyboard_arrow_down</mwc-icon> `\n }\n }\n\n _renderFilterHeader(column: ColumnConfig) {\n var filter = column.filter as FilterConfigObject\n const type = filter.type\n const idx = filter!.operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(type)[idx]\n\n return html`\n <mwc-icon\n @click=${(e: Event) => {\n const parent = (e.target as HTMLElement).closest('[column]') as HTMLElement\n const popup = parent.querySelector('ox-popup, ox-popup-list') as OxPopup | null\n // const popup = (e.target as HTMLElement).nextSibling as OxPopupList | null\n\n // absolute position인 popup의 위치 부모는 grist 이므로,\n // data-grid-header 의 포지션 부모(grist)의 위치로부터 계산해야함.\n // this의 position을 relative로 하지 못하는 이유 : ox-popup-list가 grid body에 덮히기 때문.\n const top = parent.offsetTop + parent.offsetHeight\n const right = this.clientWidth - (parent.offsetLeft + parent.offsetWidth - this.scrollLeft)\n\n popup?.open({\n right,\n top\n })\n }}\n >filter_alt</mwc-icon\n >\n\n ${!renderer\n ? html``\n : type === 'select'\n ? html`<ox-popup-list multiple attr-selected=\"checked\" with-search\n ><div filter-title slot=\"header\">\n <mwc-icon>filter_alt</mwc-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, this)}</ox-popup-list\n >`\n : html` <ox-popup\n ><div filter-title><mwc-icon>filter_alt</mwc-icon> filter by <strong>${column.name}</strong></div>\n ${renderer(column, this)}</ox-popup\n >`}\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('config')) {\n this._sorters = this.config.sorters || []\n }\n }\n\n _changeSort(column: ColumnConfig) {\n if (!column.sortable) {\n return\n }\n\n var sorters = [...this._sorters]\n\n var idx = sorters.findIndex(sorter => sorter.name == column.name)\n if (idx !== -1) {\n let sorter = sorters[idx]\n if (sorter.desc) {\n sorters.splice(idx, 1)\n } else {\n sorter.desc = true\n }\n } else {\n var sorter = {\n name: column.name\n }\n\n sorters.push(sorter)\n }\n\n this._sorters = sorters\n\n this.dispatchEvent(\n new CustomEvent('sorters-change', {\n bubbles: true,\n composed: true,\n detail: this._sorters\n })\n )\n }\n\n _accumalate(x: number) {\n this._lastAccVal = (this._lastAccVal ?? 0) + x\n return this._lastAccVal\n }\n\n _notifyWidthChange(idx: number, width: number) {\n if (!this._throttledNotifier) {\n this._throttledNotifier = throttle((idx: number, width: number) => {\n this.dispatchEvent(\n new CustomEvent('column-width-change', {\n bubbles: true,\n composed: true,\n detail: {\n idx,\n width\n }\n })\n )\n\n this._lastAccVal = 0\n }, 100)\n }\n\n this._throttledNotifier(idx, width)\n }\n\n _mousedown(e: MouseEvent, idx: number) {\n e.stopPropagation()\n e.preventDefault()\n\n var mousemoveHandler = ((e: MouseEvent) => {\n e.stopPropagation()\n e.preventDefault()\n let column = this.columns[idx]\n\n let width = Math.max(0, Number(column.width) + this._accumalate(e.movementX))\n if (width == 0) {\n /* CLARIFY-ME 왜 마지막 이벤트의 offsetX로 음수 값이 오는가 */\n return\n }\n\n this._notifyWidthChange(idx, width)\n }).bind(this)\n\n var mouseupHandler = ((e: MouseEvent) => {\n document.removeEventListener('mousemove', mousemoveHandler)\n document.removeEventListener('mouseup', mouseupHandler)\n\n mousemoveHandler(e)\n }).bind(this)\n\n document.addEventListener('mousemove', mousemoveHandler)\n document.addEventListener('mouseup', mouseupHandler)\n }\n}\n"]}
@@ -26,10 +26,12 @@ let RecordViewBody = class RecordViewBody extends LitElement {
26
26
  var rowIndex = this.rowIndex;
27
27
  return html `
28
28
  ${columns.map(column => {
29
- let { editable } = column.record;
29
+ let { editable, mandatory } = column.record;
30
30
  let dirtyFields = record['__dirtyfields__'] || {};
31
31
  return html `
32
- <label ?editable=${editable}><span>${this._renderLabel(column)}</span> <mwc-icon>edit</mwc-icon></label>
32
+ <label ?editable=${editable}
33
+ ><span>${mandatory ? '*' : ''}${this._renderLabel(column)}</span> <mwc-icon>edit</mwc-icon></label
34
+ >
33
35
  <ox-grid-field
34
36
  .rowIndex=${rowIndex}
35
37
  .column=${column}