@neovici/cosmoz-omnitable 14.12.1 → 14.12.2
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/README.md +1 -2
- package/cosmoz-omnitable-column-boolean.js +81 -62
- package/cosmoz-omnitable-column-list-data.js +57 -49
- package/cosmoz-omnitable-column-list-horizontal.js +42 -26
- package/cosmoz-omnitable-group-row.js +10 -2
- package/cosmoz-omnitable-item-expand-line.js +1 -1
- package/grouped-list/cosmoz-grouped-list-row.js +1 -1
- package/grouped-list/use-cosmoz-grouped-list.js +12 -11
- package/grouped-list/use-selected-items.js +25 -25
- package/grouped-list/use-weak-state.js +2 -2
- package/grouped-list/utils.js +11 -9
- package/lib/compute-layout.js +2 -1
- package/lib/cosmoz-omnitable-amount-range-input.js +100 -97
- package/lib/cosmoz-omnitable-date-input-mixin.js +23 -13
- package/lib/cosmoz-omnitable-date-range-input.js +85 -78
- package/lib/cosmoz-omnitable-datetime-range-input.js +85 -78
- package/lib/cosmoz-omnitable-number-range-input.js +34 -27
- package/lib/cosmoz-omnitable-range-input-mixin.js +7 -10
- package/lib/cosmoz-omnitable-time-range-input.js +54 -30
- package/lib/layout.js +12 -14
- package/lib/polymer-haunted-render-mixin.js +14 -13
- package/lib/save-as-csv-action.js +31 -27
- package/lib/save-as-xlsx-action.js +13 -11
- package/lib/settings/cosmoz-omnitable-sort-group.js +1 -1
- package/lib/settings/drivers/context.js +1 -1
- package/lib/use-hash-state.js +1 -1
- package/lib/use-processed-items.js +20 -20
- package/lib/utils-amount.js +17 -26
- package/lib/utils-data.js +24 -24
- package/lib/utils-date.js +18 -34
- package/lib/utils-datetime.js +10 -15
- package/lib/utils-number.js +28 -29
- package/lib/utils-time.js +21 -24
- package/lib/utils.js +1 -1
- package/package.json +8 -2
|
@@ -10,89 +10,96 @@ class DatetimeRangeInput extends dateInputMixin(
|
|
|
10
10
|
) {
|
|
11
11
|
// eslint-disable-next-line max-lines-per-function
|
|
12
12
|
render() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
return html`
|
|
14
|
+
<style>
|
|
15
|
+
paper-dropdown-menu {
|
|
16
|
+
--iron-icon-width: 0;
|
|
17
|
+
display: block;
|
|
18
|
+
text-align: right;
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
.dropdown-content h3 {
|
|
22
|
+
font-weight: 500;
|
|
23
|
+
font-size: 13px;
|
|
24
|
+
margin: 0;
|
|
25
|
+
font-family: var(
|
|
26
|
+
--cosmoz-input-font-family,
|
|
27
|
+
var(--paper-font-subhead_-_font-family, 'Inter', sans-serif)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
.dropdown-content {
|
|
32
|
+
padding: 10px 10px 10px 10px;
|
|
33
|
+
min-width: 120px;
|
|
34
|
+
text-align: left;
|
|
35
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
36
|
+
border-radius: 6px;
|
|
37
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
38
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
39
|
+
box-shadow:
|
|
40
|
+
0 4px 24px 0 rgba(0, 0, 0, 0.18),
|
|
41
|
+
0 1.5px 6px 0 rgba(0, 0, 0, 0.1);
|
|
42
|
+
}
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
cosmoz-datetime-input {
|
|
45
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
46
|
+
border-radius: 6px;
|
|
47
|
+
border: 1px solid #d1d1d6;
|
|
48
|
+
box-shadow: 0 1px 2px 0 rgba(60, 60, 60, 0.04);
|
|
49
|
+
padding: 2px 8px;
|
|
50
|
+
margin-bottom: 6px;
|
|
51
|
+
min-height: 28px;
|
|
52
|
+
transition:
|
|
53
|
+
border-color 0.2s,
|
|
54
|
+
box-shadow 0.2s;
|
|
55
|
+
}
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
cosmoz-datetime-input:focus-within {
|
|
58
|
+
border-color: var(--cz-accent-color, #007aff);
|
|
59
|
+
box-shadow: 0 0 0 1px rgba(0, 122, 255, 0.15);
|
|
60
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
64
|
+
<cosmoz-clear-button
|
|
65
|
+
@click=${() => this.resetFilter()}
|
|
66
|
+
?visible=${this.hasFilter()}
|
|
67
|
+
></cosmoz-clear-button>
|
|
68
|
+
<paper-dropdown-menu
|
|
69
|
+
label=${this.title}
|
|
70
|
+
placeholder=${ifDefined(this._filterText)}
|
|
71
|
+
class="external-values-${this.externalValues}"
|
|
72
|
+
title=${this._tooltip}
|
|
73
|
+
horizontal-align="right"
|
|
74
|
+
?opened=${this.headerFocused}
|
|
75
|
+
@opened-changed=${(event) =>
|
|
76
|
+
this.set('headerFocused', event.detail.value)}
|
|
77
|
+
>
|
|
78
|
+
<div class="dropdown-content" slot="dropdown-content">
|
|
79
|
+
<h3 style="margin: 0;">${this.title}</h3>
|
|
80
|
+
<cosmoz-datetime-input
|
|
81
|
+
date-label=${_('From date')}
|
|
82
|
+
time-label=${_('From time')}
|
|
83
|
+
min=${this._toInputString(this._limit.fromMin)}
|
|
84
|
+
max=${this._toInputString(this._limit.fromMax)}
|
|
85
|
+
step=${this.filterStep}
|
|
86
|
+
.value=${this._filterInput?.min}
|
|
87
|
+
@value-changed=${(event) =>
|
|
88
|
+
this.set('_filterInput.min', event.detail.value)}
|
|
89
|
+
></cosmoz-datetime-input>
|
|
90
|
+
<cosmoz-datetime-input
|
|
91
|
+
date-label=${_('To date')}
|
|
92
|
+
time-label=${_('To time')}
|
|
93
|
+
min=${this._toInputString(this._limit.toMin)}
|
|
94
|
+
max=${this._toInputString(this._limit.toMax)}
|
|
95
|
+
step=${this.filterStep}
|
|
96
|
+
.value=${this._filterInput?.max}
|
|
97
|
+
@value-changed=${(event) =>
|
|
98
|
+
this.set('_filterInput.max', event.detail.value)}
|
|
99
|
+
></cosmoz-datetime-input>
|
|
100
|
+
</div>
|
|
101
|
+
</paper-dropdown-menu>
|
|
102
|
+
`;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
_toInputString(value) {
|
|
@@ -45,40 +45,47 @@ class NumberRangeInput extends rangeInputMixin(
|
|
|
45
45
|
text-align: right;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
.dropdown-content h3 {
|
|
49
49
|
font-weight: 500;
|
|
50
50
|
font-size: 13px;
|
|
51
51
|
margin: 0;
|
|
52
|
-
font-family: var(
|
|
52
|
+
font-family: var(
|
|
53
|
+
--cosmoz-input-font-family,
|
|
54
|
+
var(--paper-font-subhead_-_font-family, 'Inter', sans-serif)
|
|
55
|
+
);
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
.dropdown-content {
|
|
59
|
+
padding: 10px 10px 10px 10px;
|
|
60
|
+
min-width: 120px;
|
|
61
|
+
text-align: left;
|
|
62
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
63
|
+
border-radius: 6px;
|
|
64
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
65
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
66
|
+
box-shadow:
|
|
67
|
+
0 4px 24px 0 rgba(0, 0, 0, 0.18),
|
|
68
|
+
0 1.5px 6px 0 rgba(0, 0, 0, 0.1);
|
|
69
|
+
}
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
cosmoz-input[type='number'] {
|
|
72
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
73
|
+
border-radius: 6px;
|
|
74
|
+
border: 1px solid #d1d1d6;
|
|
75
|
+
box-shadow: 0 1px 2px 0 rgba(60, 60, 60, 0.04);
|
|
76
|
+
padding: 2px 8px;
|
|
77
|
+
margin-bottom: 6px;
|
|
78
|
+
min-height: 28px;
|
|
79
|
+
transition:
|
|
80
|
+
border-color 0.2s,
|
|
81
|
+
box-shadow 0.2s;
|
|
82
|
+
}
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
cosmoz-input[type='number']:focus-within {
|
|
85
|
+
border-color: var(--cz-accent-color, #007aff);
|
|
86
|
+
box-shadow: 0 0 0 1px rgba(0, 122, 255, 0.15);
|
|
87
|
+
background: var(--cosmoz-omnitable-amount-input-background, #ffffff);
|
|
88
|
+
}
|
|
82
89
|
</style>
|
|
83
90
|
|
|
84
91
|
<cosmoz-clear-button
|
|
@@ -108,7 +108,6 @@ export const rangeInputMixin = (
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
112
111
|
static get observers() {
|
|
113
112
|
return [
|
|
114
113
|
'_filterInputChanged(_filterInput.*, autoupdate)',
|
|
@@ -477,14 +476,12 @@ export const rangeInputMixin = (
|
|
|
477
476
|
|
|
478
477
|
_updateLimits(limits, headerFocused) {
|
|
479
478
|
if (!limits) return;
|
|
480
|
-
Promise.resolve(invoke(limits, { active: headerFocused })).then(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
},
|
|
488
|
-
);
|
|
479
|
+
Promise.resolve(invoke(limits, { active: headerFocused })).then((res) => {
|
|
480
|
+
const { min, max } = res ?? {};
|
|
481
|
+
Object.assign(this, {
|
|
482
|
+
...(min != null ? { min } : {}),
|
|
483
|
+
...(max != null ? { max } : {}),
|
|
484
|
+
});
|
|
485
|
+
});
|
|
489
486
|
}
|
|
490
487
|
};
|
|
@@ -6,7 +6,9 @@ import '@neovici/cosmoz-input';
|
|
|
6
6
|
import { dateInputMixin } from './cosmoz-omnitable-date-input-mixin';
|
|
7
7
|
import { polymerHauntedRender } from './polymer-haunted-render-mixin';
|
|
8
8
|
|
|
9
|
-
class TimeRangeInput extends dateInputMixin(
|
|
9
|
+
class TimeRangeInput extends dateInputMixin(
|
|
10
|
+
polymerHauntedRender(PolymerElement),
|
|
11
|
+
) {
|
|
10
12
|
// eslint-disable-next-line max-lines-per-function
|
|
11
13
|
render() {
|
|
12
14
|
return html`
|
|
@@ -17,31 +19,42 @@ class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)
|
|
|
17
19
|
}
|
|
18
20
|
</style>
|
|
19
21
|
|
|
20
|
-
<cosmoz-clear-button
|
|
22
|
+
<cosmoz-clear-button
|
|
23
|
+
@click=${() => this.resetFilter()}
|
|
24
|
+
?visible=${this.hasFilter()}
|
|
25
|
+
></cosmoz-clear-button>
|
|
21
26
|
<paper-dropdown-menu
|
|
22
|
-
label=${
|
|
23
|
-
placeholder=${
|
|
24
|
-
class="external-values-${
|
|
25
|
-
title=${
|
|
27
|
+
label=${this.title}
|
|
28
|
+
placeholder=${ifDefined(this._filterText)}
|
|
29
|
+
class="external-values-${this.externalValues}"
|
|
30
|
+
title=${this._tooltip}
|
|
26
31
|
horizontal-align="right"
|
|
27
|
-
?opened=${
|
|
28
|
-
@opened-changed=${
|
|
32
|
+
?opened=${this.headerFocused}
|
|
33
|
+
@opened-changed=${(event) =>
|
|
34
|
+
this.set('headerFocused', event.detail.value)}
|
|
29
35
|
>
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
>
|
|
37
|
+
<div
|
|
38
|
+
class="dropdown-content"
|
|
39
|
+
slot="dropdown-content"
|
|
40
|
+
style="padding: 15px; min-width: 100px;"
|
|
41
|
+
>
|
|
42
|
+
<h3 style="margin: 0;">${this.title}</h3>
|
|
32
43
|
<cosmoz-input
|
|
33
44
|
type="time"
|
|
34
|
-
label=${
|
|
35
|
-
step=${
|
|
36
|
-
.value=${
|
|
37
|
-
@value-changed=${
|
|
45
|
+
label=${_('From time')}
|
|
46
|
+
step=${this.filterStep}
|
|
47
|
+
.value=${this._filterInput.min}
|
|
48
|
+
@value-changed=${(event) =>
|
|
49
|
+
this.set('_filterInput.min', event.detail.value)}
|
|
38
50
|
></cosmoz-input>
|
|
39
51
|
<cosmoz-input
|
|
40
52
|
type="time"
|
|
41
|
-
label=${
|
|
42
|
-
step=${
|
|
43
|
-
.value=${
|
|
44
|
-
@value-changed=${
|
|
53
|
+
label=${_('Until time')}
|
|
54
|
+
step=${this.filterStep}
|
|
55
|
+
.value=${this._filterInput.max}
|
|
56
|
+
@value-changed=${(event) =>
|
|
57
|
+
this.set('_filterInput.max', event.detail.value)}
|
|
45
58
|
></cosmoz-input>
|
|
46
59
|
</div>
|
|
47
60
|
</paper-dropdown-menu>
|
|
@@ -64,9 +77,10 @@ class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)
|
|
|
64
77
|
// Most browsers use local timezone when no timezone is specified
|
|
65
78
|
// but Safari uses UTC, so we set it implicitly
|
|
66
79
|
// TODO: Consider removing this when/if Safari handles local timezone correctly
|
|
67
|
-
const date =
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
const date =
|
|
81
|
+
typeof value === 'string' && value.length > 3 && value.length <= 9
|
|
82
|
+
? this.getAbsoluteISOString(this._fixedDate + 'T' + value)
|
|
83
|
+
: value;
|
|
70
84
|
return super.toDate(date, limit, limitFunc);
|
|
71
85
|
}
|
|
72
86
|
|
|
@@ -88,11 +102,15 @@ class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)
|
|
|
88
102
|
if (item == null) {
|
|
89
103
|
return;
|
|
90
104
|
}
|
|
91
|
-
let value = this._toInputString(
|
|
105
|
+
let value = this._toInputString(
|
|
106
|
+
valuePath == null ? item : this.get(valuePath, item),
|
|
107
|
+
);
|
|
92
108
|
if (value == null) {
|
|
93
109
|
return;
|
|
94
110
|
}
|
|
95
|
-
value = this.toValue(
|
|
111
|
+
value = this.toValue(
|
|
112
|
+
this.getAbsoluteISOString(this._fixedDate + 'T' + value),
|
|
113
|
+
);
|
|
96
114
|
if (value == null) {
|
|
97
115
|
return;
|
|
98
116
|
}
|
|
@@ -104,15 +122,22 @@ class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)
|
|
|
104
122
|
timeString = input.value,
|
|
105
123
|
item = e.model.item,
|
|
106
124
|
oldTime = this.toDate(item.date),
|
|
107
|
-
newTime = this.toDate(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
125
|
+
newTime = this.toDate(
|
|
126
|
+
oldTime != null
|
|
127
|
+
? oldTime.toISOString().slice(0, 10) + 'T' + timeString
|
|
128
|
+
: timeString,
|
|
129
|
+
),
|
|
130
|
+
formatFn = (value) => value;
|
|
111
131
|
if (newTime != null) {
|
|
112
132
|
return;
|
|
113
133
|
}
|
|
114
134
|
this.set(this.valuePath, newTime, item);
|
|
115
|
-
this._fireItemChangeEvent(
|
|
135
|
+
this._fireItemChangeEvent(
|
|
136
|
+
item,
|
|
137
|
+
this.valuePath,
|
|
138
|
+
oldTime,
|
|
139
|
+
formatFn.bind(this),
|
|
140
|
+
);
|
|
116
141
|
}
|
|
117
142
|
|
|
118
143
|
// OVERRIDES
|
|
@@ -121,11 +146,10 @@ class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)
|
|
|
121
146
|
const timeFormatOption = {
|
|
122
147
|
hour: 'numeric',
|
|
123
148
|
minute: 'numeric',
|
|
124
|
-
second: 'numeric'
|
|
149
|
+
second: 'numeric',
|
|
125
150
|
};
|
|
126
151
|
return new Intl.DateTimeFormat(locale || undefined, timeFormatOption);
|
|
127
152
|
}
|
|
128
153
|
}
|
|
129
154
|
|
|
130
|
-
|
|
131
155
|
customElements.define('cosmoz-omnitable-time-range-input', TimeRangeInput);
|
package/lib/layout.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
const finite = num => Number.isFinite(num) ? num : 0;
|
|
2
|
-
export const
|
|
3
|
-
// eslint-disable-next-line max-lines-per-function, max-statements
|
|
1
|
+
const finite = (num) => (Number.isFinite(num) ? num : 0);
|
|
2
|
+
export const // eslint-disable-next-line max-lines-per-function, max-statements
|
|
4
3
|
layout = (columns, container) => {
|
|
5
4
|
const result = [];
|
|
6
5
|
|
|
7
6
|
// eslint-disable-next-line one-var
|
|
8
7
|
let [widthSum, lots] = columns.reduce(
|
|
9
|
-
([widthSum, lots], { width, flex }) => [
|
|
10
|
-
|
|
11
|
-
lots + flex
|
|
12
|
-
],
|
|
13
|
-
[0, 0]
|
|
8
|
+
([widthSum, lots], { width, flex }) => [widthSum + width, lots + flex],
|
|
9
|
+
[0, 0],
|
|
14
10
|
),
|
|
15
11
|
freeRealEstate = container - widthSum,
|
|
16
12
|
lotSize = finite(freeRealEstate / lots),
|
|
@@ -21,9 +17,10 @@ export const
|
|
|
21
17
|
// first pass: apply and drop lots with minWidth or flex 0
|
|
22
18
|
for (let i = 0; i < columns.length; i++) {
|
|
23
19
|
const { width, minWidth, flex } = columns[i],
|
|
24
|
-
adjustment =
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
adjustment =
|
|
21
|
+
freeRealEstate >= 0
|
|
22
|
+
? lotSize * flex
|
|
23
|
+
: (width * freeRealEstate) / widthSum;
|
|
27
24
|
|
|
28
25
|
if (minWidth > width + adjustment) {
|
|
29
26
|
droppedWidth += width;
|
|
@@ -53,9 +50,10 @@ export const
|
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
const { width, flex } = columns[i],
|
|
56
|
-
adjustment =
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
adjustment =
|
|
54
|
+
freeRealEstate >= 0
|
|
55
|
+
? lotSize * flex
|
|
56
|
+
: (width * freeRealEstate) / widthSum;
|
|
59
57
|
|
|
60
58
|
result[i] = width + adjustment;
|
|
61
59
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { html } from '@polymer/polymer';
|
|
2
2
|
import { render } from 'lit-html';
|
|
3
3
|
|
|
4
|
-
export const polymerHauntedRender = base =>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export const polymerHauntedRender = (base) =>
|
|
5
|
+
class extends base {
|
|
6
|
+
static get template() {
|
|
7
|
+
return html`<div id="output" style="position:relative;"></div>`;
|
|
8
|
+
}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
connectedCallback() {
|
|
11
|
+
super.connectedCallback();
|
|
12
|
+
render(this.render(), this.$.output);
|
|
13
|
+
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
15
|
+
_propertiesChanged(currentProps, changedProps, oldProps) {
|
|
16
|
+
super._propertiesChanged(currentProps, changedProps, oldProps);
|
|
17
|
+
requestAnimationFrame(() => render(this.render(), this.$.output));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
import { saveAs } from 'file-saver-es';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
3
|
+
const makeCsvField = (str) => {
|
|
4
|
+
const result = str.replace(/"/gu, '""');
|
|
5
|
+
if (result.search(/("|,|\n)/gu) >= 0) {
|
|
6
|
+
return '"' + result + '"';
|
|
7
|
+
}
|
|
8
|
+
return str;
|
|
9
|
+
};
|
|
11
10
|
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
export const saveAsCsvAction = (columns, selectedItems, csvFilename) => {
|
|
12
|
+
const separator = ';',
|
|
13
|
+
lf = '\n',
|
|
14
|
+
header = columns.map((col) => makeCsvField(col.title)).join(separator) + lf,
|
|
15
|
+
rows = selectedItems.map((item) => {
|
|
16
|
+
return (
|
|
17
|
+
columns
|
|
18
|
+
.map((column) => {
|
|
19
|
+
const cell = column.getString(column, item);
|
|
20
|
+
if (cell === undefined || cell === null) {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
return makeCsvField(String(cell));
|
|
24
|
+
})
|
|
25
|
+
.join(separator) + lf
|
|
26
|
+
);
|
|
27
|
+
});
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
rows.unshift(header);
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
saveAs(
|
|
32
|
+
new File(rows, csvFilename, {
|
|
33
|
+
type: 'text/csv;charset=utf-8',
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { saveAs } from 'file-saver-es';
|
|
2
2
|
import { NullXlsx } from '@neovici/nullxlsx';
|
|
3
3
|
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
columns.map(column => {
|
|
4
|
+
export const prepareXlsxData = (columns, selectedItems) => {
|
|
5
|
+
const headers = columns.map((col) => col.title),
|
|
6
|
+
data = selectedItems.map((item) =>
|
|
7
|
+
columns.map((column) => {
|
|
9
8
|
const value = column.toXlsxValue(column, item);
|
|
10
9
|
return value == null ? '' : value;
|
|
11
|
-
})
|
|
10
|
+
}),
|
|
12
11
|
);
|
|
13
12
|
|
|
14
13
|
data.unshift(headers);
|
|
15
14
|
return data;
|
|
16
15
|
},
|
|
17
|
-
|
|
18
16
|
saveAsXlsxAction = (columns, selectedItems, xlsxFilename, xlsxSheetname) => {
|
|
19
17
|
const data = prepareXlsxData(columns, selectedItems),
|
|
20
|
-
xlsx = new NullXlsx(xlsxFilename)
|
|
18
|
+
xlsx = new NullXlsx(xlsxFilename)
|
|
19
|
+
.addSheetFromData(data, xlsxSheetname)
|
|
20
|
+
.generate();
|
|
21
21
|
|
|
22
|
-
saveAs(
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
saveAs(
|
|
23
|
+
new File([xlsx], xlsxFilename, {
|
|
24
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
25
27
|
};
|
|
@@ -8,7 +8,7 @@ export const render = ({ column, on, descending, setOn, setDescending }) => {
|
|
|
8
8
|
class="sg"
|
|
9
9
|
title=${title}
|
|
10
10
|
data-on=${ifDefined(
|
|
11
|
-
(name === on && (descending ? 'desc' : 'asc')) || undefined
|
|
11
|
+
(name === on && (descending ? 'desc' : 'asc')) || undefined,
|
|
12
12
|
)}
|
|
13
13
|
@click=${(e) => {
|
|
14
14
|
const on = e.currentTarget?.dataset.on;
|
package/lib/use-hash-state.js
CHANGED
|
@@ -49,7 +49,7 @@ export const useHashState = (
|
|
|
49
49
|
? [multiLink, multiParse]
|
|
50
50
|
: [singleLink, singleParse],
|
|
51
51
|
[state, _setState] = useState(() =>
|
|
52
|
-
param == null ? initial : parseHash(param + suffix, read) ?? initial,
|
|
52
|
+
param == null ? initial : (parseHash(param + suffix, read) ?? initial),
|
|
53
53
|
),
|
|
54
54
|
setState = useCallback(
|
|
55
55
|
(state) =>
|