@neovici/cosmoz-omnitable 7.1.0 → 8.0.0-beta.1

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 (52) hide show
  1. package/README.md +23 -0
  2. package/cosmoz-omnitable-column-amount.js +89 -320
  3. package/cosmoz-omnitable-column-autocomplete.js +36 -47
  4. package/cosmoz-omnitable-column-boolean.js +107 -209
  5. package/cosmoz-omnitable-column-date.js +89 -102
  6. package/cosmoz-omnitable-column-datetime.js +86 -119
  7. package/cosmoz-omnitable-column-list-data.js +4 -1
  8. package/cosmoz-omnitable-column-list-horizontal.js +20 -38
  9. package/cosmoz-omnitable-column-list-mixin.js +133 -140
  10. package/cosmoz-omnitable-column-list.js +19 -28
  11. package/cosmoz-omnitable-column-mixin.js +69 -447
  12. package/cosmoz-omnitable-column-number.js +91 -183
  13. package/cosmoz-omnitable-column-time.js +77 -162
  14. package/cosmoz-omnitable-column.js +49 -93
  15. package/cosmoz-omnitable-group-row.js +8 -87
  16. package/cosmoz-omnitable-header-row.js +9 -6
  17. package/cosmoz-omnitable-item-expand.js +0 -3
  18. package/cosmoz-omnitable-item-row.js +18 -127
  19. package/cosmoz-omnitable-styles.js +22 -5
  20. package/cosmoz-omnitable.js +73 -811
  21. package/lib/cosmoz-omnitable-amount-range-input.js +295 -0
  22. package/{cosmoz-omnitable-column-date-mixin.js → lib/cosmoz-omnitable-date-input-mixin.js} +4 -26
  23. package/lib/cosmoz-omnitable-date-range-input.js +81 -0
  24. package/lib/cosmoz-omnitable-datetime-range-input.js +75 -0
  25. package/lib/cosmoz-omnitable-number-range-input.js +159 -0
  26. package/{cosmoz-omnitable-column-range-mixin.js → lib/cosmoz-omnitable-range-input-mixin.js} +45 -129
  27. package/lib/cosmoz-omnitable-settings.js +22 -4
  28. package/lib/cosmoz-omnitable-time-range-input.js +130 -0
  29. package/lib/generic-sorter.js +35 -0
  30. package/lib/invoke.js +1 -0
  31. package/lib/memoize.js +54 -0
  32. package/lib/polymer-haunted-render-mixin.js +19 -0
  33. package/lib/save-as-csv-action.js +32 -0
  34. package/lib/save-as-xlsx-action.js +25 -0
  35. package/lib/use-canvas-width.js +1 -1
  36. package/lib/use-dom-columns.js +133 -0
  37. package/lib/use-hash-state.js +59 -0
  38. package/lib/use-layout.js +1 -1
  39. package/lib/use-omnitable.js +31 -4
  40. package/lib/use-processed-items.js +132 -0
  41. package/lib/use-saved-settings.js +12 -3
  42. package/lib/use-sort-and-group-options.js +30 -0
  43. package/lib/utils-amount.js +147 -0
  44. package/lib/utils-data.js +36 -0
  45. package/lib/utils-date.js +204 -0
  46. package/lib/utils-datetime.js +71 -0
  47. package/lib/utils-number.js +112 -0
  48. package/lib/utils-time.js +115 -0
  49. package/package.json +1 -1
  50. package/cosmoz-omnitable-repeater-mixin.js +0 -294
  51. package/lib/use-force-render.js +0 -8
  52. package/lib/use-render-on-column-updates.js +0 -18
@@ -3,121 +3,77 @@ import '@polymer/iron-icon/iron-icon';
3
3
  import '@polymer/paper-input/paper-input';
4
4
  import './ui-helpers/cosmoz-clear-button';
5
5
 
6
- import { columnMixin } from './cosmoz-omnitable-column-mixin';
6
+ import { applySingleFilter, columnMixin, getString } from './cosmoz-omnitable-column-mixin';
7
7
  import { PolymerElement } from '@polymer/polymer/polymer-element';
8
- import { timeOut } from '@polymer/polymer/lib/utils/async.js';
9
- import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
10
- import { enqueueDebouncer } from '@polymer/polymer/lib/utils/flush.js';
11
8
  import { html } from 'lit-html';
12
9
 
10
+ const
11
+ onChange = setState => event => setState(state => {
12
+ clearInterval(state.t);
13
+ const t = setTimeout(() => setState(state => ({ ...state, filter: state.inputValue })), 1000);
14
+ return { ...state, inputValue: event.target.value, t };
15
+ }),
16
+
17
+ onBlur = setState => () =>
18
+ setState(state => ({ ...state, filter: state.inputValue })),
19
+
20
+ onKeyDown = setState => event => {
21
+ if (event.keyCode === 13) {
22
+ event.preventDefault();
23
+ setState(state => ({ ...state, filter: state.inputValue }));
24
+ }
25
+ },
26
+
27
+ onFocus = setState => event =>
28
+ setState(state => ({ ...state, headerFocused: event.detail.value })),
29
+
30
+ resetFilter = setState => () =>
31
+ setState(state => ({ ...state, filter: undefined, inputValue: undefined })),
32
+
33
+ hasFilter = filter => filter != null && filter !== '';
34
+
13
35
  /**
14
36
  * @polymer
15
37
  * @customElement
16
38
  * @appliesMixin columnMixin
17
39
  */
18
40
  class OmnitableColumn extends columnMixin(PolymerElement) {
19
- static get is() {
20
- return 'cosmoz-omnitable-column';
21
- }
22
-
23
41
  static get properties() {
24
42
  return {
25
- minWidth: {
26
- type: String,
27
- value: '55px'
28
- },
29
-
30
- editMinWidth: {
31
- type: String,
32
- value: '55px'
33
- },
34
-
35
- inputValue: {
36
- type: Object,
37
- notify: true,
38
- value() {
39
- return this._getDefaultFilter();
40
- },
41
- observer: '_inputValueValueChanged'
42
- },
43
-
44
- _timeForNoInput: {
45
- type: Number,
46
- value: 1000
47
- }
43
+ minWidth: { type: String, value: '55px' },
44
+ editMinWidth: { type: String, value: '55px' },
45
+ inputValue: { type: Object, notify: true }
48
46
  };
49
47
  }
50
48
 
49
+ getFilterFn(column, filter) {
50
+ if (filter == null || filter === '') {
51
+ return;
52
+ }
53
+ return applySingleFilter(column, filter);
54
+ }
55
+
51
56
  renderCell(column, { item }) {
52
- return html`<span class="default-column">${ column.getString(item, column.valuePath) }</span>`;
57
+ return html`<span class="default-column">${ getString(column, item) }</span>`;
53
58
  }
54
59
 
55
- renderEditCell(column, { item }) {
56
- const onChange = event => {
57
- event.model = { item };
58
- return column._valueChanged(event);
59
- };
60
- return html`<paper-input no-label-float type="text" @change=${ onChange } .value=${ column.getString(item, column.valuePath) }></paper-input>`;
60
+ renderEditCell(column, { item }, onItemChange) {
61
+ const onChange = event => onItemChange(event.target.value);
62
+ return html`<paper-input no-label-float type="text" @change=${ onChange } .value=${ getString(column, item) }></paper-input>`;
61
63
  }
62
64
 
63
- renderHeader(column) {
65
+ renderHeader(column, { filter, inputValue, headerFocused }, setState) {
64
66
  return html`<paper-input
65
67
  label=${ column.title }
66
- .value=${ column.inputValue }
67
- @value-changed=${ event => column.inputValue = event.target.value }
68
- focused=${ column.headerFocused }
69
- @focused-changed=${ event => column.headerFocused = event.detail.value }
70
- @keydown=${ column._onKeyDown }
71
- @blur=${ column._onBlur }
68
+ .value=${ inputValue ?? filter }
69
+ @value-changed=${ onChange(setState) }
70
+ focused=${ headerFocused }
71
+ @focused-changed=${ onFocus(setState) }
72
+ @keydown=${ onKeyDown(setState) }
73
+ @blur=${ onBlur(setState) }
72
74
  >
73
- <cosmoz-clear-button suffix slot="suffix" ?visible=${ column.hasFilter() } light @click=${ () => column.resetFilter() }></cosmoz-clear-button>
75
+ <cosmoz-clear-button suffix slot="suffix" ?visible=${ hasFilter(filter) } light @click=${ resetFilter(setState) }></cosmoz-clear-button>
74
76
  </paper-input>`;
75
77
  }
76
-
77
- _serializeFilter(filter = this.filter) {
78
- return filter || null;
79
- }
80
-
81
- _deserializeFilter(obj) {
82
- return obj || null;
83
- }
84
-
85
- resetFilter() {
86
- this.filter = null;
87
- this.inputValue = null;
88
- }
89
-
90
- __filterChanged(change) {
91
- super.__filterChanged(change);
92
- if (change.value != null && change.value !== this.inputValue) {
93
- this.inputValue = change.value;
94
- }
95
- }
96
-
97
- _onBlur() {
98
- this.filter = this.inputValue;
99
- }
100
-
101
- _onKeyDown(event) {
102
- switch (event.keyCode) {
103
- case 13: // Enter
104
- event.preventDefault();
105
- this.filter = this.inputValue;
106
- break;
107
- }
108
- }
109
-
110
- _inputValueValueChanged() {
111
- if (this.inputValue === '') {
112
- this.filter = this.inputValue;
113
- return;
114
- }
115
- this._debouncer = Debouncer.debounce(this._debouncer,
116
- timeOut.after(this._timeForNoInput),
117
- () => {
118
- this.filter = this.inputValue;
119
- });
120
- enqueueDebouncer(this._debouncer);
121
- }
122
78
  }
123
- customElements.define(OmnitableColumn.is, OmnitableColumn);
79
+ customElements.define('cosmoz-omnitable-column', OmnitableColumn);
@@ -1,91 +1,12 @@
1
- import { PolymerElement } from '@polymer/polymer/polymer-element';
2
- import { html } from '@polymer/polymer/lib/utils/html-tag';
1
+ import { component } from 'haunted';
2
+ import { nothing } from 'lit-html';
3
3
 
4
- import { repeaterMixin } from './cosmoz-omnitable-repeater-mixin';
5
-
6
- /**
7
- * @polymer
8
- * @customElement
9
- * @appliesMixin repeaterMixin
10
- */
11
- class OmnitableGroupRow extends repeaterMixin(PolymerElement) {
12
- static get template() {
13
- return html`
14
- <slot name="group-row"></slot>
15
- `;
16
- }
17
-
18
- static get is() {
19
- return 'cosmoz-omnitable-group-row';
20
- }
21
-
22
- static get properties() {
23
- return {
24
- column: {
25
- type: Object,
26
- observer: '_columnChanged'
27
- },
28
-
29
- item: {
30
- type: Object
31
- },
32
-
33
- selected: {
34
- type: Boolean,
35
- observer: '_selectedChanged'
36
- },
37
-
38
- folded: {
39
- type: Boolean,
40
- observer: '_foldedChanged'
41
- }
42
- };
43
- }
44
-
45
- static get observers() {
46
- return [
47
- '_itemUpdated(item.*)'
48
- ];
49
- }
50
-
51
- get _elementType() {
52
- return 'div';
4
+ const GroupRow = ({ column, item, selected, folded }) => {
5
+ if (!column) {
6
+ return nothing;
53
7
  }
54
8
 
55
- get _slotName() {
56
- return 'group-row';
57
- }
58
-
59
- constructor() {
60
- super();
61
- this.trackColumns();
62
- }
63
-
64
- _columnChanged(newColumn) {
65
- if (!newColumn) {
66
- return;
67
- }
68
- if (this.columns && this.columns.length > 0) {
69
- this.splice('columns', 0, 1, newColumn);
70
- return;
71
- }
72
- this.columns = [newColumn];
73
- }
74
-
75
- _getRenderFn(column) {
76
- return column.renderGroup ?? column.renderCell;
77
- }
78
-
79
- _itemUpdated(changeRecord) {
80
- this.forwardPathChange(changeRecord);
81
- }
9
+ return (column.renderGroup ?? column.renderCell)(column, { item, selected, folded });
10
+ };
82
11
 
83
- _selectedChanged(selected) {
84
- this.forwardChange('selected', selected);
85
- }
86
-
87
- _foldedChanged(folded) {
88
- this.forwardChange('folded', folded);
89
- }
90
- }
91
- customElements.define(OmnitableGroupRow.is, OmnitableGroupRow);
12
+ customElements.define('cosmoz-omnitable-group-row', component(GroupRow, { useShadowDOM: false }));
@@ -1,18 +1,22 @@
1
1
  /* eslint-disable object-curly-newline */
2
2
  import { html, component } from 'haunted';
3
3
  import { repeat } from 'lit-html/directives/repeat';
4
- import { useRenderOnColumnUpdates } from './lib/use-render-on-column-updates';
5
4
  import './lib/cosmoz-omnitable-resize-nub';
6
5
 
7
6
  const
8
- renderHeaderRow = ({ columns, groupOnColumn }) => {
7
+ renderHeaderRow = ({ data, columns, groupOnColumn, filters, setFilterState }) => {
9
8
  return repeat(columns, column => column.name, column => [
10
9
  html`<div
11
10
  class="cell ${ column.headerCellClass } header-cell"
12
11
  ?hidden=${ column === groupOnColumn }
13
12
  title=${ column.title }
14
13
  name=${ column.name }
15
- >${ column.renderHeader(column) }</div>`,
14
+ >${ column.renderHeader(
15
+ column,
16
+ filters[column.name] ?? {},
17
+ state => setFilterState(column.name, state),
18
+ column.source(column, data)
19
+ ) }</div>`,
16
20
  html`<cosmoz-omnitable-resize-nub
17
21
  .column=${ column }
18
22
  name=${ column.name }
@@ -20,9 +24,8 @@ const
20
24
  ]);
21
25
  },
22
26
 
23
- HeaderRow = ({ columns, groupOnColumn, content }) => {
24
- useRenderOnColumnUpdates(columns);
25
- return [columns && renderHeaderRow({ columns, groupOnColumn }), content];
27
+ HeaderRow = ({ data, columns, groupOnColumn, content, filters, setFilterState }) => {
28
+ return [columns && renderHeaderRow({ data, columns, groupOnColumn, filters, setFilterState }), content];
26
29
  };
27
30
 
28
31
  customElements.define('cosmoz-omnitable-header-row', component(HeaderRow, { useShadowDOM: false }));
@@ -3,7 +3,6 @@ import { component, useEffect } from 'haunted';
3
3
  import {
4
4
  html, nothing
5
5
  } from 'lit-html';
6
- import { useRenderOnColumnUpdates } from './lib/use-render-on-column-updates';
7
6
  import './cosmoz-omnitable-item-expand-line';
8
7
 
9
8
  const
@@ -15,8 +14,6 @@ const
15
14
  >${ column.renderCell(column, { item, selected, expanded }) }</cosmoz-omnitable-item-expand-line>`),
16
15
 
17
16
  ExpandList = host => {
18
- useRenderOnColumnUpdates(host.columns);
19
-
20
17
  useEffect(() => {
21
18
  if (host.columns?.length > 0) {
22
19
  return;
@@ -1,129 +1,20 @@
1
- import { PolymerElement } from '@polymer/polymer/polymer-element';
2
- import { html } from '@polymer/polymer/lib/utils/html-tag';
3
-
4
- import { repeaterMixin } from './cosmoz-omnitable-repeater-mixin';
5
-
6
- /**
7
- * @polymer
8
- * @customElement
9
- * @appliesMixin repeaterMixin
10
- */
11
- class OmnitableItemRow extends repeaterMixin(PolymerElement) {
12
- static get template() {
13
- return html`
14
- <style>
15
- :host {
16
- display: flex;
17
- white-space: nowrap;
18
- }
19
-
20
- :host > ::slotted(*) {
21
- display: block;
22
- flex: none;
23
- padding: 0 3px;
24
- white-space: nowrap;
25
- overflow: hidden;
26
- text-overflow: ellipsis;
27
- box-sizing: border-box;
28
- align-self: center;
29
- }
30
-
31
- :host > ::slotted([hidden]),
32
- :host [hidden] {
33
- display: none !important;
34
- }
35
- </style>
36
- <slot name="item-cell"></slot>
37
- `;
38
- }
39
-
40
- static get is() {
41
- return 'cosmoz-omnitable-item-row';
42
- }
43
-
44
- static get properties() {
45
- return {
46
- item: {
47
- type: Object
48
- },
49
-
50
- selected: {
51
- type: Boolean,
52
- observer: '_selectedChanged'
53
- },
54
-
55
- expanded: {
56
- type: Boolean,
57
- observer: '_expandedChanged'
58
- }
59
- };
60
- }
61
-
62
- static get observers() {
63
- return [
64
- '_itemUpdated(item.*)'
65
- ];
66
- }
67
-
68
- get _elementType() {
69
- return 'div';
70
- }
71
-
72
- get _slotName() {
73
- return 'item-cell';
74
- }
75
-
76
- constructor() {
77
- super();
78
- this.trackColumns();
79
- }
80
-
81
- _getRenderFn(column) {
82
- return column.editable
83
- ? column.renderEditCell
84
- : column.renderCell;
85
- }
86
-
87
- /**
88
- * @inheritdoc
89
- */
90
- _configureElement(element, column, instance) {
91
- super._configureElement(element, column, instance);
92
- element.style.minHeight = '0.5px';
93
- element.toggleAttribute('editable', !!column.editable);
94
- element.setAttribute('title', this._getCellTitle(column, this.item));
95
- element.setAttribute('class', this._computeItemRowCellClasses(column));
96
- element.setAttribute('name', column.name);
97
- }
98
-
99
- _itemUpdated(changeRecord) {
100
- this.forwardPathChange(changeRecord);
101
- this.forEachElement((element, column) => {
102
- element.setAttribute('title', this._getCellTitle(column, this.item));
1
+ import { component, html } from 'haunted';
2
+ import { repeat } from 'lit-html/directives/repeat';
3
+
4
+ const
5
+ renderCell = (column, data, onItemChange) => column.editable
6
+ ? column.renderEditCell(column, data, onItemChange(column, data.item))
7
+ : column.renderCell(column, data),
8
+ ItemRow = ({ columns, groupOnColumn, item, selected, expanded, onItemChange }) => {
9
+ return repeat(columns, column => column.name, column => {
10
+ return html`<div
11
+ class="cell itemRow-cell ${ column.cellClass ?? '' }"
12
+ ?hidden=${ column === groupOnColumn }
13
+ ?editable=${ column.editable }
14
+ title=${ column.cellTitleFn(column, item) }
15
+ name=${ column.name }
16
+ >${ renderCell(column, { item, selected, expanded }, onItemChange) }</div>`;
103
17
  });
104
- }
105
-
106
- _selectedChanged(selected) {
107
- this.forwardChange('selected', selected);
108
- }
109
-
110
- _expandedChanged(expanded) {
111
- this.forwardChange('expanded', expanded);
112
- }
113
-
114
- /**
115
- * Get cell title displayed when hovering on the cell.
116
- * @param {object} column Column data.
117
- * @param {object} item Row item.
118
- * @returns {string} Cell title.
119
- */
120
- _getCellTitle(column, item) {
121
- return column && column.cellTitleFn(item, column.valuePath);
122
- }
18
+ };
123
19
 
124
- _computeItemRowCellClasses(column) {
125
- return 'cell itemRow-cell'
126
- + (column.cellClass ? ' ' + column.cellClass + ' ' : '');
127
- }
128
- }
129
- customElements.define(OmnitableItemRow.is, OmnitableItemRow);
20
+ customElements.define('cosmoz-omnitable-item-row', component(ItemRow, { useShadowDOM: false }));
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-lines */
1
2
  const checkbox = `
2
3
  .checkbox {
3
4
  box-sizing: border-box;
@@ -160,6 +161,27 @@ export default `<style>
160
161
  position: relative;
161
162
  }
162
163
 
164
+
165
+ cosmoz-omnitable-item-row {
166
+ display: flex;
167
+ white-space: nowrap;
168
+ }
169
+
170
+ cosmoz-omnitable-item-row > div {
171
+ display: block;
172
+ flex: none;
173
+ padding: 0 3px;
174
+ white-space: nowrap;
175
+ overflow: hidden;
176
+ text-overflow: ellipsis;
177
+ box-sizing: border-box;
178
+ align-self: center;
179
+ }
180
+
181
+ cosmoz-omnitable-item-row > div[hidden] {
182
+ display: none !important;
183
+ }
184
+
163
185
  .tableContent {
164
186
  overflow-y: auto;
165
187
  min-height: 90px;
@@ -315,11 +337,6 @@ export default `<style>
315
337
  @apply --cosmoz-omnitable-selected-row;
316
338
  }
317
339
 
318
- .itemRow[highlighted] {
319
- background-color: rgba(195, 212, 248, 0.5);
320
- @apply --cosmoz-omnitable-hightlighted-row;
321
- }
322
-
323
340
  .tableContent .itemRow-cell paper-dropdown-menu {
324
341
  margin-top:-20px;
325
342
  }