@neovici/cosmoz-omnitable 7.2.1 → 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 (50) 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 +1 -5
  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 +5 -8
  19. package/cosmoz-omnitable-styles.js +1 -5
  20. package/cosmoz-omnitable.js +72 -763
  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 -123
  27. package/lib/cosmoz-omnitable-settings.js +7 -4
  28. package/lib/cosmoz-omnitable-time-range-input.js +130 -0
  29. package/lib/generic-sorter.js +2 -2
  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 +26 -14
  40. package/lib/use-processed-items.js +132 -0
  41. package/lib/use-sort-and-group-options.js +30 -0
  42. package/lib/utils-amount.js +147 -0
  43. package/lib/utils-data.js +36 -0
  44. package/lib/utils-date.js +204 -0
  45. package/lib/utils-datetime.js +71 -0
  46. package/lib/utils-number.js +112 -0
  47. package/lib/utils-time.js +115 -0
  48. package/package.json +1 -1
  49. package/lib/use-force-render.js +0 -8
  50. package/lib/use-render-on-column-updates.js +0 -18
@@ -5,222 +5,130 @@ import './ui-helpers/cosmoz-clear-button';
5
5
  import { PolymerElement } from '@polymer/polymer/polymer-element';
6
6
  import { html } from 'lit-html';
7
7
 
8
- import {
9
- translatable, _
10
- } from '@neovici/cosmoz-i18next';
11
8
  import { columnMixin } from './cosmoz-omnitable-column-mixin';
12
- import { rangeColumnMixin } from './cosmoz-omnitable-column-range-mixin';
13
- import { ifDefined } from 'lit-html/directives/if-defined';
9
+
10
+ import './lib/cosmoz-omnitable-number-range-input';
11
+ import { valuesFrom } from './lib/utils-data';
12
+ import { applySingleFilter, getComparableValue, getInputString, getString, toHashString, toNumber } from './lib/utils-number';
13
+ import { get } from '@polymer/polymer/lib/utils/path';
14
+
14
15
 
15
16
  /**
16
17
  * @polymer
17
18
  * @customElement
18
- * @appliesMixin rangeColumnMixin
19
19
  * @appliesMixin columnMixin
20
20
  */
21
- class OmnitableColumnNumber extends rangeColumnMixin(
22
- columnMixin(
23
- translatable(
24
- PolymerElement
25
- )
26
- )
27
- ) {
28
- static get is() {
29
- return 'cosmoz-omnitable-column-number';
30
- }
31
-
21
+ class OmnitableColumnNumber extends columnMixin(PolymerElement) {
32
22
  static get properties() {
33
23
  return {
34
- cellClass: {
35
- type: String,
36
- value: 'number-cell align-right'
37
- },
38
- width: {
39
- type: String,
40
- value: '30px'
41
- },
42
- minWidth: {
43
- type: String,
44
- value: '30px'
45
- },
46
- editWidth: {
47
- type: String,
48
- value: '30px'
49
- },
50
- headerCellClass: {
51
- type: String,
52
- value: 'number-header-cell'
53
- },
54
- maximumFractionDigits: {
55
- type: Number,
56
- value: null
57
- },
58
- minimumFractionDigits: {
59
- type: Number,
60
- value: null // browser default 0 for numbers, currency-specific or 2 for currency
61
- },
62
- formatter: {
63
- type: Object,
64
- computed: '_computeFormatter(locale, minimumFractionDigits, maximumFractionDigits)'
65
- },
66
- // trigger filter updates manually
67
- autoupdate: {
68
- type: String,
69
- value: false
70
- },
71
- _filterText: {
72
- type: String,
73
- computed: '_computeFilterText(filter.*, formatter)'
74
- }
24
+ min: { type: Number, value: null, notify: true },
25
+ max: { type: Number, value: null, notify: true },
26
+ locale: { type: String, value: null, notify: true },
27
+ autoupdate: { type: Boolean, value: false, notify: true },
28
+ cellClass: { type: String, value: 'number-cell align-right' },
29
+ width: { type: String, value: '30px' },
30
+ minWidth: { type: String, value: '30px' },
31
+ headerCellClass: { type: String, value: 'number-header-cell' },
32
+ maximumFractionDigits: { type: Number, value: null },
33
+ minimumFractionDigits: { type: Number, value: null } // browser default 0 for numbers, currency-specific or 2 for currency
75
34
  };
76
35
  }
77
36
 
78
- _computeFormatter(locale, minimumFractionDigits, maximumFractionDigits) {
79
- const options = {
80
- localeMatcher: 'best fit' // chrome expects this when using custom options
81
- };
82
- if (minimumFractionDigits !== null) {
83
- options.minimumFractionDigits = minimumFractionDigits;
84
- }
85
- if (maximumFractionDigits !== null) {
86
- options.maximumFractionDigits = maximumFractionDigits;
87
- }
88
- return new Intl.NumberFormat(locale || undefined, options);
89
- }
37
+ getFilterFn(column, filter) {
38
+ const
39
+ min = getComparableValue(filter, 'min', column),
40
+ max = getComparableValue(filter, 'max', column);
90
41
 
91
- /**
92
- * Check if label should float based on validity
93
- *
94
- * Number inputs can have allowed characters that aren't numbers (-,e) and won't
95
- * trigger a value change and thus not float the label.
96
- * However, the validity will report badInput so we can trigger a label float by
97
- * setting it to something truthy but still not visible.
98
- * Fixed in paper-input 3.x
99
- *
100
- * @param {Event} event KeyboardEvent
101
- * @returns {void}
102
- */
103
- onBadInputFloatLabel(event) {
104
- const paperInput = event.currentTarget;
105
- if (paperInput == null || paperInput.tagName !== 'PAPER-INPUT') {
42
+ if (min == null && max == null) {
106
43
  return;
107
44
  }
108
- paperInput.placeholder = paperInput.$.nativeInput.validity.badInput ? ' ' : '';
45
+ return applySingleFilter(column, filter);
46
+ }
47
+
48
+ getString(column, item) {
49
+ return getString(column, item);
50
+ }
51
+
52
+ toXlsxValue({ valuePath }, item) {
53
+ return get(item, valuePath);
54
+ }
55
+
56
+ cellTitleFn(column, item) {
57
+ return getString(column, item);
109
58
  }
110
59
 
111
- /**
112
- * Get the comparable value of an item.
113
- *
114
- * @param {Object} item Item to be processed
115
- * @param {String} valuePath Property path
116
- * @returns {Number|void} Valid value or void
117
- */
118
- getComparableValue(item, valuePath) {
119
- if (item == null) {
60
+ getComparableValue(item, valuePath, column) {
61
+ return getComparableValue(item, valuePath, column);
62
+ }
63
+
64
+ serializeFilter(column, filter) {
65
+ if (filter == null) {
120
66
  return;
121
67
  }
122
- let value = item;
123
- if (valuePath != null) {
124
- value = this.get(valuePath, item);
125
- }
126
- value = this.toValue(value);
127
- if (value == null) {
68
+ const min = toNumber(filter.min),
69
+ max = toNumber(filter.max);
70
+
71
+ if (min == null && max == null) {
128
72
  return;
129
73
  }
74
+ return toHashString(min) + '~' + toHashString(max);
75
+ }
130
76
 
131
- const decimals = this.maximumFractionDigits;
132
- if (decimals !== null) {
133
- return this.toValue(value.toFixed(decimals));
77
+ deserializeFilter(column, filter) {
78
+ if (filter == null || filter === '') {
79
+ return null;
134
80
  }
135
- return value;
136
- }
81
+ const matches = filter.match(/^([^~]+)?~([^~]+)?/iu);
137
82
 
138
- renderValue(value, formatter = this.formatter) {
139
- const number = this.toNumber(value);
140
- if (number == null) {
141
- return;
83
+ if (!Array.isArray(matches)) {
84
+ return null;
142
85
  }
143
- return formatter.format(number);
86
+
87
+ return {
88
+ min: toNumber(matches[1]),
89
+ max: toNumber(matches[2])
90
+ };
144
91
  }
145
92
 
146
93
  renderCell(column, { item }) {
147
- return html`<div class="omnitable-cell-number">${ column.getString(item, column.valuePath, column.formatter) }</div>`;
94
+ return html`<div class="omnitable-cell-number">${ getString(column, item) }</div>`;
148
95
  }
149
96
 
150
- renderEditCell(column, { item }) {
151
- const onChange = event => {
152
- event.model = { item };
153
- return column._valueChanged(event);
154
- };
97
+ renderEditCell(column, { item }, onItemChange) {
98
+ const onChange = event => onItemChange(event.target.value);
155
99
 
156
- return html`<paper-input no-label-float type="number" @change=${ onChange } .value=${ column.getInputString(item, column.valuePath) }></paper-input>`;
100
+ return html`<paper-input no-label-float type="number" @change=${ onChange } .value=${ getInputString(column, item) }></paper-input>`;
157
101
  }
158
102
 
159
- // eslint-disable-next-line max-lines-per-function
160
- renderHeader(column) {
161
- const onOpenedChanged = event => {
162
- column.headerFocused = event.detail.value;
163
- column._onDropdownOpenedChanged(event);
164
- };
103
+ renderHeader(
104
+ { title,
105
+ min,
106
+ max,
107
+ locale,
108
+ maximumFractionDigits,
109
+ minimumFractionDigits,
110
+ autoupdate },
111
+ { filter },
112
+ setState,
113
+ source
114
+ ) {
115
+ return html`<cosmoz-omnitable-number-range-input
116
+ .title=${ title }
117
+ .filter=${ filter }
118
+ .values=${ source }
119
+ .min=${ min }
120
+ .max=${ max }
121
+ .locale=${ locale }
122
+ .maximumFractionDigits=${ maximumFractionDigits }
123
+ .minimumFractionDigsits=${ minimumFractionDigits }
124
+ .autoupdate=${ autoupdate }
125
+ @filter-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, filter: value })) }
126
+ @header-focused-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, headerFocused: value })) }
127
+ ></cosmoz-omnitable-number-range-input>`;
128
+ }
165
129
 
166
- return html`
167
- <style>
168
- paper-input > iron-icon {
169
- display: none;
170
- cursor: pointer;
171
- }
172
-
173
- paper-input.has-value > iron-icon {
174
- display: block;
175
- }
176
-
177
- paper-dropdown-menu {
178
- --iron-icon-width: 0;
179
- }
180
- </style>
181
- <cosmoz-clear-button @click=${ event => column.resetFilter(event) } ?visible=${ column.hasFilter() }></cosmoz-clear-button>
182
- <paper-dropdown-menu
183
- label=${ column.title }
184
- placeholder=${ ifDefined(column._filterText) }
185
- class="external-values-${ column.externalValues }"
186
- title=${ column._tooltip }
187
- horizontal-align=${ column.preferredDropdownHorizontalAlign }
188
- ?opened=${ column.headerFocused }
189
- @opened-changed=${ onOpenedChanged }
190
- >
191
- <div class="dropdown-content" slot="dropdown-content" style="padding: 15px; min-width: 100px;">
192
- <h3 style="margin: 0;">${ column.title }</h3>
193
- <paper-input
194
- class=${ column._fromClasses }
195
- type="number"
196
- label=${ _('From') }
197
- .value=${ column._filterInput.min }
198
- @value-changed=${ event => column.set('_filterInput.min', event.detail.value) }
199
- @input=${ event => column.onBadInputFloatLabel(event) }
200
- @blur=${ event => column._onBlur(event) }
201
- @keydown=${ event => column._onKeyDown(event) }
202
- min=${ column._toInputString(column._limit.fromMin) }
203
- max=${ column._toInputString(column._limit.fromMax) }
204
- >
205
- <iron-icon icon="clear" slot="suffix" @tap=${ event => column._clearFrom(event) }></iron-icon>
206
- </paper-input>
207
- <paper-input
208
- class=${ column._toClasses }
209
- type="number"
210
- label=${ _('To') }
211
- .value=${ column._filterInput.max }
212
- @value-changed=${ event => column.set('_filterInput.max', event.detail.value) }
213
- @input=${ event => column.onBadInputFloatLabel(event) }
214
- @blur=${ event => column._onBlur(event) }
215
- @keydown=${ event => column._onKeyDown(event) }
216
- min=${ column._toInputString(column._limit.toMin) }
217
- max=${ column._toInputString(column._limit.toMax) }
218
- >
219
- <iron-icon icon="clear" slot="suffix" @tap=${ event => column._clearTo(event) }></iron-icon>
220
- </paper-input>
221
- </div>
222
- </paper-dropdown-menu>
223
- `;
130
+ computeSource({ valuePath }, data) {
131
+ return valuesFrom(data, valuePath);
224
132
  }
225
133
  }
226
- customElements.define(OmnitableColumnNumber.is, OmnitableColumnNumber);
134
+ customElements.define('cosmoz-omnitable-column-number', OmnitableColumnNumber);
@@ -7,210 +7,125 @@ import './ui-helpers/cosmoz-clear-button';
7
7
  import { PolymerElement } from '@polymer/polymer/polymer-element';
8
8
  import { html } from 'lit-html';
9
9
 
10
- import {
11
- translatable, _
12
- } from '@neovici/cosmoz-i18next';
13
10
  import { columnMixin } from './cosmoz-omnitable-column-mixin';
14
- import { dateColumnMixin } from './cosmoz-omnitable-column-date-mixin';
15
- import { ifDefined } from 'lit-html/directives/if-defined';
11
+ import { getComparableValue, getString, toXlsxValue, applySingleFilter, toDate, toHashString, fromHashString } from './lib/utils-time';
12
+ import './lib/cosmoz-omnitable-time-range-input';
13
+ import { valuesFrom } from './lib/utils-data';
16
14
 
17
15
  /**
18
16
  * @polymer
19
17
  * @customElement
20
- * @appliesMixin dateColumnMixin
21
18
  * @appliesMixin columnMixin
22
19
  */
23
- class OmnitableColumnTime extends
24
- dateColumnMixin(
25
- columnMixin(
26
- translatable(PolymerElement)
27
- )
28
- ) {
29
- static get is() {
30
- return 'cosmoz-omnitable-column-time';
31
- }
32
-
20
+ class OmnitableColumnTime extends columnMixin(PolymerElement) {
33
21
  static get properties() {
34
22
  return {
23
+ min: { type: Number, value: null, notify: true },
24
+ max: { type: Number, value: null, notify: true },
25
+ locale: { type: String, value: null, notify: true },
26
+ headerCellClass: { type: String, value: 'time-header-cell' },
27
+ minWidth: { type: String, value: '63px' },
28
+ width: { type: String, value: '210px' },
29
+ flex: { type: String, value: '0' },
35
30
  /*
36
31
  * Specifies the value granularity of the time input's value in the filter.
37
32
  * 1 => full seconds
38
33
  * 0.1 => milliseconds
39
34
  */
40
- filterStep: {
41
- type: String,
42
- value: '1'
43
- },
44
-
45
- headerCellClass: {
46
- type: String,
47
- value: 'time-header-cell'
48
- },
49
-
50
- minWidth: {
51
- type: String,
52
- value: '63px'
53
- },
54
-
55
- editMinWidth: {
56
- type: String,
57
- value: '63px'
58
- }
35
+ filterStep: { type: String, value: '1' }
59
36
  };
60
37
  }
61
38
 
62
- renderCell(column, { item }) {
63
- return column.getString(item, column.valuePath, column.formatter);
64
- }
65
-
66
- renderEditCell(column, { item }) {
67
- const onChange = event => {
68
- event.model = { item };
69
- return column._timeValueChanged(event);
70
- };
39
+ getFilterFn(column, filter) {
40
+ const
41
+ min = getComparableValue(filter, 'min', column),
42
+ max = getComparableValue(filter, 'max', column);
71
43
 
72
- return html`<paper-input
73
- no-label-float
74
- type="time"
75
- @change=${ onChange }
76
- .value=${ column.getInputString(item, column.valuePath) }
77
- ></paper-input>`;
44
+ if (min == null && max == null) {
45
+ return;
46
+ }
47
+ return applySingleFilter(column, filter);
78
48
  }
79
49
 
80
- renderHeader(column) {
81
- return html`
82
- <cosmoz-clear-button @click=${ event => column.resetFilter(event) } ?visible=${ column.hasFilter() }></cosmoz-clear-button>
83
- <paper-dropdown-menu
84
- label=${ column.title }
85
- placeholder=${ ifDefined(column._filterText) }
86
- class="external-values-${ column.externalValues }"
87
- title=${ column._tooltip }
88
- horizontal-align=${ column.preferredDropdownHorizontalAlign }
89
- ?opened=${ column.headerFocused }
90
- @opened-changed=${ event => column.headerFocused = event.detail.value }>
91
- >
92
- <div class="dropdown-content" slot="dropdown-content" style="padding: 15px; min-width: 100px;">
93
- <h3 style="margin: 0;">${ column.title }</h3>
94
- <paper-input
95
- type="time"
96
- label=${ _('From time') }
97
- step=${ column.filterStep }
98
- .value=${ column._filterInput.min }
99
- @value-changed=${ event => column.set('_filterInput.min', event.detail.value) }
100
- ></paper-input>
101
- <paper-input
102
- type="time"
103
- label=${ _('Until time') }
104
- step=${ column.filterStep }
105
- .value=${ column._filterInput.max }
106
- @value-changed=${ event => column.set('_filterInput.max', event.detail.value) }
107
- ></paper-input>
108
- </div>
109
- </paper-dropdown-menu>
110
- `;
50
+ getString(column, item) {
51
+ return getString(column, item);
111
52
  }
112
53
 
113
- get _fixedDate() {
114
- return '1970-01-01';
54
+ toXlsxValue(column, item) {
55
+ return toXlsxValue(column, item);
115
56
  }
116
57
 
117
- /**
118
- * Converts time to date optionaly limiting it.
119
- *
120
- * @param {Date|Number} value Date or Timestamp ( miliseconds since property _fixedDate ) to be converted
121
- * @param {Date|Number} limit Optional value to limit the date.
122
- * @param {Function} limitFunc Function used to limit the date (Math.min|Math.max)
123
- * @returns {Date|void} Value converted to date optionaly limitated
124
- */
125
- toDate(value, limit, limitFunc) {
126
- // Most browsers use local timezone when no timezone is specified
127
- // but Safari uses UTC, so we set it implicitly
128
- // TODO: Consider removing this when/if Safari handles local timezone correctly
129
- const date = typeof value === 'string' && value.length > 3 && value.length <= 9
130
- ? this.getAbsoluteISOString(this._fixedDate + 'T' + value)
131
- : value;
132
- return super.toDate(date, limit, limitFunc);
58
+ cellTitleFn(column, item) {
59
+ return getString(column, item);
133
60
  }
134
61
 
135
- _toInputString(value) {
136
- const date = this.toValue(value);
137
- if (date == null) {
138
- return null;
139
- }
140
- return this._toLocalISOString(date).slice(11, 19);
62
+ getComparableValue(item, valuePath, column) {
63
+ return getComparableValue(item, valuePath, column);
141
64
  }
142
65
 
143
- _toHashString(value) {
144
- const date = this.toValue(value);
145
- if (date == null) {
146
- return '';
66
+ serializeFilter(column, filter) {
67
+ if (filter == null) {
68
+ return;
147
69
  }
148
- //Use utc in hash
149
- return date.toISOString().slice(11, 19).replace(/:/gu, '.');
150
- }
70
+ const min = toDate(filter.min),
71
+ max = toDate(filter.max);
151
72
 
152
- _fromHashString(value) {
153
- if (value == null || value === '') {
73
+ if (min == null && max == null) {
154
74
  return;
155
75
  }
156
- //Parse utc from hash string
157
- return this.toValue(value.replace(/\./gu, ':') + 'Z');
76
+ return toHashString(min) + '~' + toHashString(max);
158
77
  }
159
78
 
160
- /**
161
- * Get the comparable value of an item.
162
- *
163
- * @param {Object} item Item to be processed
164
- * @param {String} valuePath Property path
165
- * @returns {Number|void} Valid value or void
166
- */
167
- getComparableValue(item, valuePath) {
168
- if (item == null) {
169
- return;
170
- }
171
- let value = this._toInputString(valuePath == null ? item : this.get(valuePath, item));
172
- if (value == null) {
173
- return;
79
+ deserializeFilter(column, filter) {
80
+ if (filter == null || filter === '') {
81
+ return null;
174
82
  }
175
- value = this.toValue(this.getAbsoluteISOString(this._fixedDate + 'T' + value));
176
- if (value == null) {
177
- return;
83
+ const matches = filter.match(/^([^~]+)?~([^~]+)?/iu);
84
+
85
+ if (!Array.isArray(matches)) {
86
+ return null;
178
87
  }
179
- return this.toNumber(value.getTime());
88
+
89
+ return {
90
+ min: fromHashString(matches[1]),
91
+ max: fromHashString(matches[2])
92
+ };
180
93
  }
181
94
 
182
- toXlsxValue(item, valuePath = this.valuePath) {
183
- if (!valuePath) {
184
- return '';
185
- }
186
- return this.getString(item, valuePath);
95
+ renderCell(column, { item }) {
96
+ return getString(column, item);
187
97
  }
188
98
 
189
- _timeValueChanged(e) {
190
- const input = e.target,
191
- timeString = input.value,
192
- item = e.model.item,
193
- oldTime = this.toDate(item.date),
194
- newTime = this.toDate(oldTime != null
195
- ? oldTime.toISOString().slice(0, 10) + 'T' + timeString
196
- : timeString),
197
- formatFn = value => value;
198
- if (newTime != null) {
199
- return;
200
- }
201
- this.set(this.valuePath, newTime, item);
202
- this._fireItemChangeEvent(item, this.valuePath, oldTime, formatFn.bind(this));
99
+ renderEditCell(column, { item }, onItemChange) {
100
+ const onChange = event => onItemChange(event.target.value);
101
+ return html`<paper-input no-label-float type="text" @change=${ onChange } .value=${ getString(column, item) }></paper-input>`;
203
102
  }
204
103
 
205
- // OVERRIDES
104
+ renderHeader(
105
+ { title,
106
+ min,
107
+ max,
108
+ locale,
109
+ filterStep },
110
+ { filter },
111
+ setState,
112
+ source
113
+ ) {
114
+ return html`<cosmoz-omnitable-time-range-input
115
+ .title=${ title }
116
+ .filter=${ filter }
117
+ .values=${ source }
118
+ .min=${ min }
119
+ .max=${ max }
120
+ .locale=${ locale }
121
+ .filterStep=${ filterStep }
122
+ @filter-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, filter: value })) }
123
+ @header-focused-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, headerFocused: value })) }
124
+ ></cosmoz-omnitable-time-range-input>`;
125
+ }
206
126
 
207
- _computeFormatter(locale) {
208
- const timeFormatOption = {
209
- hour: 'numeric',
210
- minute: 'numeric',
211
- second: 'numeric'
212
- };
213
- return new Intl.DateTimeFormat(locale || undefined, timeFormatOption);
127
+ computeSource({ valuePath }, data) {
128
+ return valuesFrom(data, valuePath);
214
129
  }
215
130
  }
216
- customElements.define(OmnitableColumnTime.is, OmnitableColumnTime);
131
+ customElements.define('cosmoz-omnitable-column-time', OmnitableColumnTime);