@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
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
cosmoz-omnitable
|
|
2
|
-
=================
|
|
1
|
+
# cosmoz-omnitable
|
|
3
2
|
|
|
4
3
|
[](https://github.com/Neovici/cosmoz-omnitable/actions?workflow=Github+CI)
|
|
5
4
|
[](https://codecov.io/gh/Neovici/cosmoz-omnitable)
|
|
@@ -4,65 +4,49 @@ import { columnMixin } from './cosmoz-omnitable-column-mixin';
|
|
|
4
4
|
|
|
5
5
|
import '@polymer/paper-spinner/paper-spinner-lite';
|
|
6
6
|
import '@neovici/cosmoz-autocomplete';
|
|
7
|
-
import {
|
|
8
|
-
html, nothing
|
|
9
|
-
} from 'lit-html';
|
|
7
|
+
import { html, nothing } from 'lit-html';
|
|
10
8
|
import { get } from '@polymer/polymer/lib/utils/path';
|
|
11
9
|
import { memooize } from '@neovici/cosmoz-utils/memoize';
|
|
12
10
|
|
|
13
|
-
const
|
|
14
|
-
computeValue = (value, source) =>
|
|
11
|
+
const computeValue = (value, source) =>
|
|
15
12
|
source.find(({ value: valueProp }) => value === valueProp),
|
|
16
|
-
|
|
17
13
|
computeTooltip = (title, value, source) => {
|
|
18
14
|
const val = computeValue(value, source);
|
|
19
15
|
return val ? val.text : title;
|
|
20
16
|
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
get(item, valuePath),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
computeItemValue = ({ valuePath }, item, source) => computeValue(
|
|
29
|
-
get(item, valuePath),
|
|
30
|
-
source
|
|
31
|
-
),
|
|
32
|
-
|
|
33
|
-
onChange = setState => selection => {
|
|
34
|
-
setState(state => ({ ...state, filter: selection?.[0]?.value ?? null }));
|
|
17
|
+
computeItemTooltip = (title, item, valuePath, source) =>
|
|
18
|
+
computeTooltip(title, get(item, valuePath), source),
|
|
19
|
+
computeItemValue = ({ valuePath }, item, source) =>
|
|
20
|
+
computeValue(get(item, valuePath), source),
|
|
21
|
+
onChange = (setState) => (selection) => {
|
|
22
|
+
setState((state) => ({ ...state, filter: selection?.[0]?.value ?? null }));
|
|
35
23
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
setState(state => ({ ...state, headerFocused: focused }));
|
|
24
|
+
onFocus = (setState) => (focused) => {
|
|
25
|
+
setState((state) => ({ ...state, headerFocused: focused }));
|
|
39
26
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
setState(state => ({ ...state, query: text }));
|
|
27
|
+
onText = (setState) => (text) => {
|
|
28
|
+
setState((state) => ({ ...state, query: text }));
|
|
43
29
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
30
|
+
onEditableChange = (onItemChange) => (selection) =>
|
|
31
|
+
onItemChange(selection?.[0]?.value),
|
|
47
32
|
getString = ({ valuePath, trueLabel, falseLabel }, item) => {
|
|
48
33
|
const value = get(item, valuePath);
|
|
49
34
|
return value ? trueLabel : falseLabel;
|
|
50
35
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
36
|
+
applySingleFilter =
|
|
37
|
+
({ valuePath }, filter) =>
|
|
38
|
+
(item) =>
|
|
39
|
+
get(item, valuePath) === filter,
|
|
54
40
|
computeSource = memooize((trueLabel, falseLabel) => [
|
|
55
41
|
{ text: trueLabel, value: true },
|
|
56
|
-
{ text: falseLabel, value: false }
|
|
42
|
+
{ text: falseLabel, value: false },
|
|
57
43
|
]),
|
|
58
|
-
|
|
59
44
|
toXlsxValue = ({ valuePath, trueLabel, falseLabel }, item) => {
|
|
60
45
|
if (!valuePath) {
|
|
61
46
|
return '';
|
|
62
47
|
}
|
|
63
48
|
return get(item, valuePath) ? trueLabel : falseLabel;
|
|
64
49
|
},
|
|
65
|
-
|
|
66
50
|
deserializeFilter = (column, filter) => {
|
|
67
51
|
try {
|
|
68
52
|
return JSON.parse(filter);
|
|
@@ -82,7 +66,7 @@ class OmnitableColumnBoolean extends columnMixin(PolymerElement) {
|
|
|
82
66
|
trueLabel: { type: String, value: 'True' },
|
|
83
67
|
falseLabel: { type: String, value: 'False' },
|
|
84
68
|
flex: { type: String, value: '0' },
|
|
85
|
-
cellClass: { type: String, value: 'boolean-cell' }
|
|
69
|
+
cellClass: { type: String, value: 'boolean-cell' },
|
|
86
70
|
};
|
|
87
71
|
}
|
|
88
72
|
|
|
@@ -99,40 +83,65 @@ class OmnitableColumnBoolean extends columnMixin(PolymerElement) {
|
|
|
99
83
|
}
|
|
100
84
|
|
|
101
85
|
renderEditCell(column, { item }, onItemChange) {
|
|
102
|
-
const
|
|
103
|
-
{ trueLabel, falseLabel } = column,
|
|
86
|
+
const { trueLabel, falseLabel } = column,
|
|
104
87
|
spinner = column.loading
|
|
105
|
-
? html`<paper-spinner-lite
|
|
88
|
+
? html`<paper-spinner-lite
|
|
89
|
+
style="width: 20px; height: 20px;"
|
|
90
|
+
suffix
|
|
91
|
+
slot="suffix"
|
|
92
|
+
active
|
|
93
|
+
></paper-spinner-lite>`
|
|
106
94
|
: nothing;
|
|
107
95
|
|
|
108
96
|
return html`<cosmoz-autocomplete
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
97
|
+
no-label-float
|
|
98
|
+
.title=${computeItemTooltip(
|
|
99
|
+
column.title,
|
|
100
|
+
item,
|
|
101
|
+
column.valuePath,
|
|
102
|
+
computeSource(trueLabel, falseLabel),
|
|
103
|
+
)}
|
|
104
|
+
.source=${computeSource(trueLabel, falseLabel)}
|
|
105
|
+
.textProperty=${'text'}
|
|
106
|
+
.value=${computeItemValue(
|
|
107
|
+
column,
|
|
108
|
+
item,
|
|
109
|
+
computeSource(trueLabel, falseLabel),
|
|
110
|
+
)}
|
|
111
|
+
.onChange=${onEditableChange(onItemChange)}
|
|
112
|
+
.limit=${1}
|
|
113
|
+
>${spinner}</cosmoz-autocomplete
|
|
114
|
+
>`;
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
renderHeader(column, { filter, query }, setState, source) {
|
|
120
118
|
const spinner = column.loading
|
|
121
|
-
? html`<paper-spinner-lite
|
|
119
|
+
? html`<paper-spinner-lite
|
|
120
|
+
style="width: 20px; height: 20px;"
|
|
121
|
+
suffix
|
|
122
|
+
slot="suffix"
|
|
123
|
+
active
|
|
124
|
+
></paper-spinner-lite>`
|
|
122
125
|
: nothing;
|
|
123
126
|
|
|
124
127
|
return html`<cosmoz-autocomplete-ui
|
|
125
|
-
.label=${
|
|
126
|
-
.title=${
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
.
|
|
133
|
-
.
|
|
134
|
-
.
|
|
135
|
-
|
|
128
|
+
.label=${column.title}
|
|
129
|
+
.title=${computeItemTooltip(
|
|
130
|
+
column.title,
|
|
131
|
+
filter,
|
|
132
|
+
column.valuePath,
|
|
133
|
+
source,
|
|
134
|
+
)}
|
|
135
|
+
.source=${source}
|
|
136
|
+
.textProperty=${'text'}
|
|
137
|
+
.value=${computeValue(filter, source)}
|
|
138
|
+
.text=${query}
|
|
139
|
+
.onChange=${onChange(setState)}
|
|
140
|
+
.onFocus=${onFocus(setState)}
|
|
141
|
+
.onText=${onText(setState)}
|
|
142
|
+
.limit=${1}
|
|
143
|
+
>${spinner}</cosmoz-autocomplete-ui
|
|
144
|
+
>`;
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
computeSource({ trueLabel, falseLabel }) {
|
|
@@ -154,6 +163,16 @@ class OmnitableColumnBoolean extends columnMixin(PolymerElement) {
|
|
|
154
163
|
return deserializeFilter(column, filter);
|
|
155
164
|
}
|
|
156
165
|
}
|
|
157
|
-
customElements.define(
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
customElements.define(
|
|
167
|
+
'cosmoz-omnitable-column-boolean',
|
|
168
|
+
OmnitableColumnBoolean,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
export {
|
|
172
|
+
getString,
|
|
173
|
+
computeItemValue,
|
|
174
|
+
computeSource,
|
|
175
|
+
toXlsxValue,
|
|
176
|
+
onChange,
|
|
177
|
+
deserializeFilter,
|
|
178
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { translatable } from '@neovici/cosmoz-i18next';
|
|
2
|
-
import {
|
|
3
|
-
mixin, Template
|
|
4
|
-
} from '@neovici/cosmoz-utils';
|
|
2
|
+
import { mixin, Template } from '@neovici/cosmoz-utils';
|
|
5
3
|
|
|
6
4
|
import { PolymerElement } from '@polymer/polymer/polymer-element';
|
|
7
5
|
import { html } from '@polymer/polymer/lib/utils/html-tag';
|
|
@@ -12,51 +10,59 @@ window.Cosmoz = window.Cosmoz || {};
|
|
|
12
10
|
* @customElement
|
|
13
11
|
* @appliesMixin translatable
|
|
14
12
|
*/
|
|
15
|
-
class OmnitableColumnListData extends translatable(
|
|
13
|
+
class OmnitableColumnListData extends translatable(
|
|
14
|
+
mixin(Template, PolymerElement),
|
|
15
|
+
) {
|
|
16
16
|
static get template() {
|
|
17
17
|
return html`
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<li>
|
|
45
|
-
<span>[[ _firstItem(items) ]]</span>
|
|
46
|
-
</li>
|
|
47
|
-
<li class="see-more" hidden$="[[_hideExpand(items, _expanded)]]">
|
|
48
|
-
<a href="#" on-tap="_toggleExpand">[[ _('and {0} more', _othersCount, t) ]]</a>
|
|
49
|
-
</li>
|
|
50
|
-
<template is="dom-repeat" items="[[ _otherItems(items, _expanded) ]]" as="item">
|
|
18
|
+
<style>
|
|
19
|
+
:host {
|
|
20
|
+
display: block;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:host a {
|
|
24
|
+
color: var(--primary-link-color, inherit);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
[hidden] {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ul {
|
|
32
|
+
list-style-type: none;
|
|
33
|
+
margin: 0.3em 0;
|
|
34
|
+
padding-left: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
li {
|
|
38
|
+
text-overflow: ellipsis;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
|
|
43
|
+
<ul hidden$="[[ isEmpty(items) ]]">
|
|
51
44
|
<li>
|
|
52
|
-
<span
|
|
45
|
+
<span>[[ _firstItem(items) ]]</span>
|
|
46
|
+
</li>
|
|
47
|
+
<li class="see-more" hidden$="[[_hideExpand(items, _expanded)]]">
|
|
48
|
+
<a href="#" on-tap="_toggleExpand"
|
|
49
|
+
>[[ _('and {0} more', _othersCount, t) ]]</a
|
|
50
|
+
>
|
|
53
51
|
</li>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
<template
|
|
53
|
+
is="dom-repeat"
|
|
54
|
+
items="[[ _otherItems(items, _expanded) ]]"
|
|
55
|
+
as="item"
|
|
56
|
+
>
|
|
57
|
+
<li>
|
|
58
|
+
<span class="item">[[ item ]]</span>
|
|
59
|
+
</li>
|
|
60
|
+
</template>
|
|
61
|
+
<li class="see-less" hidden$="[[ _hideCollapse(items, _expanded) ]]">
|
|
62
|
+
<a href="#" on-tap="_toggleExpand">[[ _('See less', t) ]]</a>
|
|
63
|
+
</li>
|
|
64
|
+
</ul>
|
|
65
|
+
`;
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
static get is() {
|
|
@@ -71,22 +77,24 @@ class OmnitableColumnListData extends translatable(mixin(Template, PolymerElemen
|
|
|
71
77
|
|
|
72
78
|
_expanded: {
|
|
73
79
|
type: Boolean,
|
|
74
|
-
value: false
|
|
80
|
+
value: false,
|
|
75
81
|
},
|
|
76
82
|
|
|
77
83
|
_othersCount: {
|
|
78
84
|
type: Number,
|
|
79
|
-
computed: '_computeOthersCount(items)'
|
|
80
|
-
}
|
|
85
|
+
computed: '_computeOthersCount(items)',
|
|
86
|
+
},
|
|
81
87
|
};
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
static get observers() {
|
|
85
|
-
return ['_itemsLengthChanged(items.length)']
|
|
91
|
+
return ['_itemsLengthChanged(items.length)'];
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
_itemsLengthChanged() {
|
|
89
|
-
requestAnimationFrame(() =>
|
|
95
|
+
requestAnimationFrame(() =>
|
|
96
|
+
this.dispatchEvent(new CustomEvent('expand', { bubbles: true })),
|
|
97
|
+
);
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
_firstItem(items) {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import '@neovici/cosmoz-autocomplete';
|
|
2
2
|
|
|
3
3
|
import { PolymerElement } from '@polymer/polymer/polymer-element';
|
|
4
|
-
import {
|
|
5
|
-
html, nothing
|
|
6
|
-
} from 'lit-html';
|
|
4
|
+
import { html, nothing } from 'lit-html';
|
|
7
5
|
|
|
8
6
|
import { columnMixin } from './cosmoz-omnitable-column-mixin';
|
|
9
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
getTexts,
|
|
9
|
+
listColumnMixin,
|
|
10
|
+
onChange,
|
|
11
|
+
onFocus,
|
|
12
|
+
onText,
|
|
13
|
+
} from './cosmoz-omnitable-column-list-mixin';
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* @polymer
|
|
@@ -14,9 +18,13 @@ import { getTexts, listColumnMixin, onChange, onFocus, onText } from './cosmoz-o
|
|
|
14
18
|
* @appliesMixin listColumnMixin
|
|
15
19
|
* @appliesMixin columnMixin
|
|
16
20
|
*/
|
|
17
|
-
class OmnitableColumnListHorizontal extends listColumnMixin(
|
|
21
|
+
class OmnitableColumnListHorizontal extends listColumnMixin(
|
|
22
|
+
columnMixin(PolymerElement),
|
|
23
|
+
) {
|
|
18
24
|
renderCell({ valuePath, textProperty }, { item }) {
|
|
19
|
-
const list = getTexts(item, valuePath, textProperty).map(
|
|
25
|
+
const list = getTexts(item, valuePath, textProperty).map(
|
|
26
|
+
(item) => html`<li>${item}</li>`,
|
|
27
|
+
);
|
|
20
28
|
|
|
21
29
|
return html`
|
|
22
30
|
<style>
|
|
@@ -29,13 +37,15 @@ class OmnitableColumnListHorizontal extends listColumnMixin(columnMixin(PolymerE
|
|
|
29
37
|
display: inline;
|
|
30
38
|
}
|
|
31
39
|
ul li:after {
|
|
32
|
-
content:
|
|
40
|
+
content: ', ';
|
|
33
41
|
}
|
|
34
42
|
ul li:last-child:after {
|
|
35
|
-
content:
|
|
43
|
+
content: '';
|
|
36
44
|
}
|
|
37
45
|
</style>
|
|
38
|
-
<ul
|
|
46
|
+
<ul>
|
|
47
|
+
${list}
|
|
48
|
+
</ul>
|
|
39
49
|
`;
|
|
40
50
|
}
|
|
41
51
|
|
|
@@ -44,24 +54,30 @@ class OmnitableColumnListHorizontal extends listColumnMixin(columnMixin(PolymerE
|
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
renderHeader(column, { filter, query }, setState, source) {
|
|
47
|
-
const
|
|
48
|
-
spinner
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
const spinner = column.loading
|
|
58
|
+
? html`<paper-spinner-lite
|
|
59
|
+
style="width: 20px; height: 20px;"
|
|
60
|
+
suffix
|
|
61
|
+
slot="suffix"
|
|
62
|
+
active
|
|
63
|
+
></paper-spinner-lite>`
|
|
64
|
+
: nothing;
|
|
51
65
|
return html`<cosmoz-autocomplete-ui
|
|
52
|
-
class="external-values-${
|
|
53
|
-
.label=${
|
|
54
|
-
.source=${
|
|
55
|
-
.textProperty=${
|
|
56
|
-
.value=${
|
|
57
|
-
.text=${
|
|
58
|
-
.onChange=${
|
|
59
|
-
.onFocus=${
|
|
60
|
-
.onText=${
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
class="external-values-${column.externalValues}"
|
|
67
|
+
.label=${column.title}
|
|
68
|
+
.source=${source}
|
|
69
|
+
.textProperty=${column.textProperty}
|
|
70
|
+
.value=${filter}
|
|
71
|
+
.text=${query}
|
|
72
|
+
.onChange=${onChange(setState)}
|
|
73
|
+
.onFocus=${onFocus(setState)}
|
|
74
|
+
.onText=${onText(setState)}
|
|
75
|
+
>${spinner}</cosmoz-autocomplete-ui
|
|
76
|
+
> `;
|
|
63
77
|
}
|
|
64
|
-
|
|
65
78
|
}
|
|
66
79
|
|
|
67
|
-
customElements.define(
|
|
80
|
+
customElements.define(
|
|
81
|
+
'cosmoz-omnitable-column-list-horizontal',
|
|
82
|
+
OmnitableColumnListHorizontal,
|
|
83
|
+
);
|
|
@@ -6,7 +6,15 @@ const GroupRow = ({ column, item, selected, folded, group }) => {
|
|
|
6
6
|
return nothing;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
return (column.renderGroup ?? column.renderCell)(column, {
|
|
9
|
+
return (column.renderGroup ?? column.renderCell)(column, {
|
|
10
|
+
item,
|
|
11
|
+
selected,
|
|
12
|
+
folded,
|
|
13
|
+
group,
|
|
14
|
+
});
|
|
10
15
|
};
|
|
11
16
|
|
|
12
|
-
customElements.define(
|
|
17
|
+
customElements.define(
|
|
18
|
+
'cosmoz-omnitable-group-row',
|
|
19
|
+
component(GroupRow, { useShadowDOM: false }),
|
|
20
|
+
);
|
|
@@ -30,7 +30,7 @@ const styles = {
|
|
|
30
30
|
// suggested fix: separate signal for item collapse and group fold
|
|
31
31
|
flatData = useMemo(
|
|
32
32
|
() => prepareData(data, displayEmptyGroups, state),
|
|
33
|
-
[data, displayEmptyGroups, signal]
|
|
33
|
+
[data, displayEmptyGroups, signal],
|
|
34
34
|
),
|
|
35
35
|
{
|
|
36
36
|
selectedItems,
|
|
@@ -60,21 +60,21 @@ const styles = {
|
|
|
60
60
|
toggleSelect: (selected) =>
|
|
61
61
|
toggleSelect(
|
|
62
62
|
item,
|
|
63
|
-
typeof selected === 'boolean' ? selected : undefined
|
|
63
|
+
typeof selected === 'boolean' ? selected : undefined,
|
|
64
64
|
),
|
|
65
65
|
toggleFold: () => toggleFold(item),
|
|
66
|
-
|
|
66
|
+
})
|
|
67
67
|
: renderItem(item, index, {
|
|
68
68
|
selected: selectedItems.includes(item),
|
|
69
69
|
expanded: isExpanded(item, state),
|
|
70
70
|
toggleSelect: (selected) =>
|
|
71
71
|
toggleSelect(
|
|
72
72
|
item,
|
|
73
|
-
typeof selected === 'boolean' ? selected : undefined
|
|
73
|
+
typeof selected === 'boolean' ? selected : undefined,
|
|
74
74
|
),
|
|
75
75
|
toggleCollapse: () => toggleCollapse(item),
|
|
76
|
-
|
|
77
|
-
[renderItem, renderGroup, selectedItems, toggleSelect, signal]
|
|
76
|
+
}),
|
|
77
|
+
[renderItem, renderGroup, selectedItems, toggleSelect, signal],
|
|
78
78
|
);
|
|
79
79
|
|
|
80
80
|
useLayoutEffect(() => Object.assign(host.style, styles.host), []);
|
|
@@ -105,11 +105,12 @@ const styles = {
|
|
|
105
105
|
renderCosmozGroupedList = ({ renderRow, flatData }) =>
|
|
106
106
|
virtualize({
|
|
107
107
|
items: flatData,
|
|
108
|
-
renderItem: (item, index) =>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
renderItem: (item, index) =>
|
|
109
|
+
html`<cosmoz-grouped-list-row
|
|
110
|
+
.item=${item}
|
|
111
|
+
.index=${index}
|
|
112
|
+
.renderFn=${renderRow}
|
|
113
|
+
></cosmoz-grouped-list-row>`,
|
|
113
114
|
});
|
|
114
115
|
|
|
115
116
|
export { renderCosmozGroupedList, useCosmozGroupedList };
|
|
@@ -6,7 +6,7 @@ export const useSelectedItems = ({
|
|
|
6
6
|
initial,
|
|
7
7
|
compareItemsFn,
|
|
8
8
|
data,
|
|
9
|
-
flatData
|
|
9
|
+
flatData,
|
|
10
10
|
}) => {
|
|
11
11
|
const [selectedItems, setSelectedItems] = useState(initial),
|
|
12
12
|
[lastSelection, setLastSelection] = useState(),
|
|
@@ -16,8 +16,8 @@ export const useSelectedItems = ({
|
|
|
16
16
|
* @returns {boolean} Whether item is selected.
|
|
17
17
|
*/
|
|
18
18
|
isItemSelected = useCallback(
|
|
19
|
-
item => selectedItems.includes(item),
|
|
20
|
-
[selectedItems]
|
|
19
|
+
(item) => selectedItems.includes(item),
|
|
20
|
+
[selectedItems],
|
|
21
21
|
),
|
|
22
22
|
/**
|
|
23
23
|
* Check if group is selected.
|
|
@@ -25,8 +25,8 @@ export const useSelectedItems = ({
|
|
|
25
25
|
* @returns {boolean} Whether group is selected.
|
|
26
26
|
*/
|
|
27
27
|
isGroupSelected = useCallback(
|
|
28
|
-
group => group?.items?.every(isItemSelected),
|
|
29
|
-
[isItemSelected]
|
|
28
|
+
(group) => group?.items?.every(isItemSelected),
|
|
29
|
+
[isItemSelected],
|
|
30
30
|
),
|
|
31
31
|
/**
|
|
32
32
|
* Check if item.group is selected.
|
|
@@ -34,19 +34,19 @@ export const useSelectedItems = ({
|
|
|
34
34
|
* @returns {boolean} Whether item is selected.
|
|
35
35
|
*/
|
|
36
36
|
isSelected = useCallback(
|
|
37
|
-
item => isItemSelected(item) || isGroupSelected(item),
|
|
38
|
-
[isItemSelected, isGroupSelected]
|
|
37
|
+
(item) => isItemSelected(item) || isGroupSelected(item),
|
|
38
|
+
[isItemSelected, isGroupSelected],
|
|
39
39
|
),
|
|
40
40
|
/**
|
|
41
41
|
* Add an item/group to the list of selected items.
|
|
42
42
|
* @param {object} item Item to select.
|
|
43
43
|
* @returns {void}
|
|
44
44
|
*/
|
|
45
|
-
select = useCallback(item => {
|
|
45
|
+
select = useCallback((item) => {
|
|
46
46
|
const items = item.items ?? [item];
|
|
47
|
-
setSelectedItems(selection => [
|
|
47
|
+
setSelectedItems((selection) => [
|
|
48
48
|
...selection,
|
|
49
|
-
...items.filter(i => !selection.includes(i))
|
|
49
|
+
...items.filter((i) => !selection.includes(i)),
|
|
50
50
|
]);
|
|
51
51
|
setLastSelection(item);
|
|
52
52
|
}, []),
|
|
@@ -55,14 +55,14 @@ export const useSelectedItems = ({
|
|
|
55
55
|
* @param {object} item Item to select.
|
|
56
56
|
* @returns {void}
|
|
57
57
|
*/
|
|
58
|
-
deselect = useCallback(item => {
|
|
58
|
+
deselect = useCallback((item) => {
|
|
59
59
|
const items = item.items ?? [item];
|
|
60
|
-
setSelectedItems(selection =>
|
|
61
|
-
selection.filter(i => !items.includes(i))
|
|
60
|
+
setSelectedItems((selection) =>
|
|
61
|
+
selection.filter((i) => !items.includes(i)),
|
|
62
62
|
);
|
|
63
63
|
setLastSelection(item);
|
|
64
64
|
}, []),
|
|
65
|
-
selectOnly = useCallback(item => {
|
|
65
|
+
selectOnly = useCallback((item) => {
|
|
66
66
|
setSelectedItems(item.items?.slice() || [item]);
|
|
67
67
|
setLastSelection(item);
|
|
68
68
|
}, []),
|
|
@@ -71,7 +71,7 @@ export const useSelectedItems = ({
|
|
|
71
71
|
* @returns {void}
|
|
72
72
|
*/
|
|
73
73
|
selectAll = useCallback(() => {
|
|
74
|
-
setSelectedItems(data.flatMap(item => item.items || item));
|
|
74
|
+
setSelectedItems(data.flatMap((item) => item.items || item));
|
|
75
75
|
setLastSelection(undefined);
|
|
76
76
|
}, [data]),
|
|
77
77
|
/**
|
|
@@ -91,12 +91,12 @@ export const useSelectedItems = ({
|
|
|
91
91
|
toggleSelect = useCallback(
|
|
92
92
|
(item, selected = !isSelected(item)) =>
|
|
93
93
|
selected ? select(item) : deselect(item),
|
|
94
|
-
[isSelected]
|
|
94
|
+
[isSelected],
|
|
95
95
|
),
|
|
96
96
|
toggleSelectTo = useCallback(
|
|
97
97
|
(item, selected) => {
|
|
98
98
|
const last = lastSelection
|
|
99
|
-
? flatData.findIndex(i => compareItemsFn(i, lastSelection))
|
|
99
|
+
? flatData.findIndex((i) => compareItemsFn(i, lastSelection))
|
|
100
100
|
: -1;
|
|
101
101
|
if (last < 0) {
|
|
102
102
|
return toggleSelect(item, selected);
|
|
@@ -110,20 +110,20 @@ export const useSelectedItems = ({
|
|
|
110
110
|
});
|
|
111
111
|
setLastSelection(item);
|
|
112
112
|
},
|
|
113
|
-
[flatData, compareItemsFn, toggleSelect]
|
|
113
|
+
[flatData, compareItemsFn, toggleSelect],
|
|
114
114
|
);
|
|
115
115
|
|
|
116
116
|
// keep selected items across data updates
|
|
117
117
|
useEffect(
|
|
118
118
|
() =>
|
|
119
|
-
setSelectedItems(selectedItems =>
|
|
119
|
+
setSelectedItems((selectedItems) =>
|
|
120
120
|
selectedItems.length > 0
|
|
121
|
-
? flatData.filter(i =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
: selectedItems
|
|
121
|
+
? flatData.filter((i) =>
|
|
122
|
+
selectedItems.find((item) => compareItemsFn(i, item)),
|
|
123
|
+
)
|
|
124
|
+
: selectedItems,
|
|
125
125
|
),
|
|
126
|
-
[flatData]
|
|
126
|
+
[flatData],
|
|
127
127
|
);
|
|
128
128
|
return {
|
|
129
129
|
selectedItems,
|
|
@@ -136,6 +136,6 @@ export const useSelectedItems = ({
|
|
|
136
136
|
selectAll,
|
|
137
137
|
deselectAll,
|
|
138
138
|
toggleSelect,
|
|
139
|
-
toggleSelectTo
|
|
139
|
+
toggleSelectTo,
|
|
140
140
|
};
|
|
141
141
|
};
|