@kubex/zinc 1.0.12 → 1.0.14
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/dist/custom-elements.json +2611 -2187
- package/dist/vscode.html-custom-data.json +185 -155
- package/dist/web-types.json +420 -334
- package/dist/zn.d.ts +133 -15
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +603 -551
- package/docs/pages/components/data-select.md +1 -1
- package/docs/pages/components/filter-container.md +72 -0
- package/docs/pages/components/filter-wrapper.md +2 -2
- package/docs/pages/components/hover-container.md +20 -0
- package/docs/pages/components/reveal.md +24 -0
- package/docs/pages/components/select.md +39 -1
- package/docs/pages/components/toggle.md +6 -3
- package/package.json +1 -1
- package/scss/_root.scss +4 -4
- package/src/components/button/button.component.ts +11 -5
- package/src/components/content-block/content-block.scss +35 -23
- package/src/components/data-select/data-select.component.ts +5 -2
- package/src/components/data-table/data-table.component.ts +128 -27
- package/src/components/data-table/data-table.scss +56 -10
- package/src/components/dropdown/dropdown.component.ts +3 -0
- package/src/components/editor/editor.component.ts +1 -1
- package/src/components/filter-container/filter-container.component.ts +112 -0
- package/src/components/filter-container/filter-container.scss +5 -0
- package/src/components/filter-container/filter-container.test.ts +10 -0
- package/src/components/filter-container/index.ts +12 -0
- package/src/components/filter-wrapper/filter-wrapper.component.ts +1 -1
- package/src/components/form-group/form-group.component.ts +26 -26
- package/src/components/header/header.scss +7 -0
- package/src/components/navbar/navbar.scss +4 -0
- package/src/components/note/note.component.ts +1 -0
- package/src/components/option/option.component.ts +3 -3
- package/src/components/option/option.scss +5 -9
- package/src/components/progress-bar/progress-bar.component.ts +1 -1
- package/src/components/progress-tile/progress-tile.component.ts +2 -2
- package/src/components/reveal/index.ts +12 -0
- package/src/components/reveal/reveal.component.ts +92 -0
- package/src/components/reveal/reveal.scss +18 -0
- package/src/components/reveal/reveal.test.ts +10 -0
- package/src/components/select/select.component.ts +63 -7
- package/src/components/sp/sp.component.ts +2 -0
- package/src/components/split-pane/split-pane.component.ts +2 -1
- package/src/components/tile/tile.component.ts +3 -1
- package/src/components/toggle/toggle.component.ts +33 -23
- package/src/components/tooltip/tooltip.component.ts +10 -5
- package/src/internal/form.ts +5 -0
- package/src/utilities/top-layer-manager.ts +32 -0
- package/src/wc.scss +9 -5
- package/src/zinc.ts +2 -0
|
@@ -8,7 +8,7 @@ layout: component
|
|
|
8
8
|
```html:preview
|
|
9
9
|
|
|
10
10
|
<div class="form-spacing">
|
|
11
|
-
<zn-data-select label="Country" provider="country" name="country"></zn-data-select>
|
|
11
|
+
<zn-data-select label="Country" provider="country" name="country" multiple></zn-data-select>
|
|
12
12
|
<zn-data-select label="Currency" provider="currency" name="currency"></zn-data-select>
|
|
13
13
|
<zn-data-select label="Color" provider="color" name="color"></zn-data-select>
|
|
14
14
|
</div>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
meta:
|
|
3
|
+
title: Filter Container
|
|
4
|
+
description:
|
|
5
|
+
layout: component
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
```html:preview
|
|
9
|
+
|
|
10
|
+
<zn-filter-container>
|
|
11
|
+
<zn-sp flush>
|
|
12
|
+
<zn-panel caption="Section One">
|
|
13
|
+
<div style="display: flex; flex-direction: column;">
|
|
14
|
+
<div data-filter="John Doe"
|
|
15
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
16
|
+
<strong>John Doe</strong>
|
|
17
|
+
<span>john.doe@zinc.style</span>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div data-filter="Gary Smith"
|
|
21
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
22
|
+
<strong>Gary Smith</strong>
|
|
23
|
+
<span>gary.smith@zinc.style</span>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div data-filter="Lisa Wong"
|
|
27
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
28
|
+
<strong>Lisa Wong</strong>
|
|
29
|
+
<span>lisa.wong@zinc.style</span>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div data-filter="Emma Johnson"
|
|
33
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
34
|
+
<strong>Emma Johnson</strong>
|
|
35
|
+
<span>emma.johnson@zinc.style</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
</zn-panel>
|
|
40
|
+
|
|
41
|
+
<zn-panel caption="Section Two">
|
|
42
|
+
<div style="display: flex; flex-direction: column;">
|
|
43
|
+
<div data-filter="Michael Brown"
|
|
44
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
45
|
+
<strong>Michael Brown</strong>
|
|
46
|
+
<span>michael.brown@zinc.style</span>
|
|
47
|
+
</div>
|
|
48
|
+
<div data-filter="Sophia Davis"
|
|
49
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
50
|
+
<strong>Sophia Davis</strong>
|
|
51
|
+
<span>sophia.davis@zinc.style</span>
|
|
52
|
+
</div>
|
|
53
|
+
<div data-filter="Lisa Wong"
|
|
54
|
+
style="padding: 10px 0; display: flex; flex-direction: column; border-bottom: 1px solid grey;">
|
|
55
|
+
<strong>Lisa Wong</strong>
|
|
56
|
+
<span>lisa.wong@zinc.style</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</zn-panel>
|
|
60
|
+
</zn-sp>
|
|
61
|
+
</zn-filter-container>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
### First Example
|
|
67
|
+
|
|
68
|
+
TODO
|
|
69
|
+
|
|
70
|
+
### Second Example
|
|
71
|
+
|
|
72
|
+
TODO
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
meta:
|
|
3
|
+
title: Reveal
|
|
4
|
+
description:
|
|
5
|
+
layout: component
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
```html:preview
|
|
9
|
+
|
|
10
|
+
<zn-reveal duration="3000"
|
|
11
|
+
initial="******@hotmail.com"
|
|
12
|
+
revealed="john.doe@hotmail.com">
|
|
13
|
+
</zn-reveal>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Examples
|
|
17
|
+
|
|
18
|
+
### First Example
|
|
19
|
+
|
|
20
|
+
TODO
|
|
21
|
+
|
|
22
|
+
### Second Example
|
|
23
|
+
|
|
24
|
+
TODO
|
|
@@ -39,6 +39,44 @@ This component works with standard `<form>` elements. Please refer to the sectio
|
|
|
39
39
|
on [form controls](/getting-started/form-controls) to learn more about form submission and client-side validation.
|
|
40
40
|
:::
|
|
41
41
|
|
|
42
|
+
### Distinct Selects
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
```html:preview
|
|
46
|
+
|
|
47
|
+
<div class="form-spacing">
|
|
48
|
+
<zn-select provider="country" multiple name="country-one" id="country-one" distinct="country-two">
|
|
49
|
+
<zn-option value="0">Option 0</zn-option>
|
|
50
|
+
<zn-option value="1">Option 1</zn-option>
|
|
51
|
+
<zn-option value="2">Option 2</zn-option>
|
|
52
|
+
</zn-select>
|
|
53
|
+
<zn-select provider="country" multiple name="country-two" id="country-two" distinct="country-one">
|
|
54
|
+
<zn-option value="0">Option 0</zn-option>
|
|
55
|
+
<zn-option value="1">Option 1</zn-option>
|
|
56
|
+
<zn-option value="2">Option 2</zn-option>
|
|
57
|
+
</zn-select>
|
|
58
|
+
</div>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Conditional Selects
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
```html:preview
|
|
65
|
+
|
|
66
|
+
<div class="form-spacing">
|
|
67
|
+
<zn-select provider="conditional" multiple name="conditional-one" id="conditional-one" conditional="conditional-two">
|
|
68
|
+
<zn-option value="0">Option 0</zn-option>
|
|
69
|
+
<zn-option value="1">Option 1</zn-option>
|
|
70
|
+
<zn-option value="2">Option 2</zn-option>
|
|
71
|
+
</zn-select>
|
|
72
|
+
<zn-select provider="conditional" multiple name="conditional-two" id="conditional-two" conditional="conditional-one">
|
|
73
|
+
<zn-option value="0">Option 0</zn-option>
|
|
74
|
+
<zn-option value="1">Option 1</zn-option>
|
|
75
|
+
<zn-option value="2">Option 2</zn-option>
|
|
76
|
+
</zn-select>
|
|
77
|
+
</div>
|
|
78
|
+
```
|
|
79
|
+
|
|
42
80
|
### Help Text
|
|
43
81
|
|
|
44
82
|
Add descriptive help text to a select with the `help-text` attribute. For help texts that contain HTML, use the
|
|
@@ -124,7 +162,7 @@ the most common for selects), include an empty option that people can select to
|
|
|
124
162
|
:::
|
|
125
163
|
|
|
126
164
|
```html:preview
|
|
127
|
-
<zn-select label="Clearable multi-choice select" clearable multiple
|
|
165
|
+
<zn-select label="Clearable multi-choice select" clearable multiple help-text="For multi-choice selects only, display an icon button to let people clear their selections">
|
|
128
166
|
<zn-option value="option-1">Option 1</zn-option>
|
|
129
167
|
<zn-option value="option-2">Option 2</zn-option>
|
|
130
168
|
<zn-option value="option-3">Option 3</zn-option>
|
|
@@ -6,14 +6,17 @@ layout: component
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
```html:preview
|
|
9
|
-
<zn-toggle
|
|
9
|
+
<zn-toggle></zn-toggle>
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
## Examples
|
|
13
13
|
|
|
14
|
-
###
|
|
14
|
+
### With Tooltip
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
```html:preview
|
|
17
|
+
|
|
18
|
+
<zn-toggle on-text="Available" off-text="Unavailable" label="Status"></zn-toggle>
|
|
19
|
+
```
|
|
17
20
|
|
|
18
21
|
### Second Example
|
|
19
22
|
|
package/package.json
CHANGED
package/scss/_root.scss
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
:root {
|
|
7
7
|
// Brand Colors
|
|
8
8
|
--zn-red: 237, 84, 109;
|
|
9
|
-
--zn-blue: 100,
|
|
10
|
-
--zn-green:
|
|
9
|
+
--zn-blue: 100, 117, 242;
|
|
10
|
+
--zn-green: 43, 192, 145;
|
|
11
11
|
--zn-orange: 255, 136, 0;
|
|
12
12
|
--zn-yellow: 255, 193, 7;
|
|
13
13
|
--zn-indigo: 63, 81, 181;
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
--zn-accent: 71, 214, 214;
|
|
19
19
|
|
|
20
20
|
// Theme Colors
|
|
21
|
-
--zn-color-info: 100,
|
|
21
|
+
--zn-color-info: 100, 117, 242;
|
|
22
22
|
--zn-color-warning: 255, 136, 0;
|
|
23
23
|
--zn-color-error: 237, 84, 109;
|
|
24
|
-
--zn-color-success:
|
|
24
|
+
--zn-color-success: 43, 192, 145;
|
|
25
25
|
--zn-color-disabled: 181, 181, 181;
|
|
26
26
|
|
|
27
27
|
// Common Sizes
|
|
@@ -5,6 +5,7 @@ import {HasSlotController} from '../../internal/slot';
|
|
|
5
5
|
import {html, literal} from 'lit/static-html.js';
|
|
6
6
|
import {ifDefined} from 'lit/directives/if-defined.js';
|
|
7
7
|
import {property, query, queryAll} from 'lit/decorators.js';
|
|
8
|
+
import {watch} from '../../internal/watch';
|
|
8
9
|
import ZincElement from '../../internal/zinc-element';
|
|
9
10
|
import ZnDropdown from "../dropdown";
|
|
10
11
|
import ZnIcon from "../icon";
|
|
@@ -137,13 +138,18 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
|
|
|
137
138
|
this.teardownAutoClick();
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
@watch('autoClick')
|
|
142
|
+
async handleAutoClickChange(_old: boolean, value: boolean) {
|
|
143
|
+
if (value) {
|
|
144
|
+
await this.updateComplete;
|
|
145
|
+
this.setupAutoClick();
|
|
146
|
+
} else {
|
|
147
|
+
this.teardownAutoClick();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
140
151
|
protected updated(changedProps: Map<string, any>) {
|
|
141
152
|
super.updated(changedProps);
|
|
142
|
-
if (changedProps.has('autoClick')) {
|
|
143
|
-
if (this.autoClick) {
|
|
144
|
-
this.setupAutoClick();
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
153
|
if (this.button) {
|
|
148
154
|
const oldOverlay = this.button.querySelector('.button--loading-fill');
|
|
149
155
|
if (oldOverlay) {
|
|
@@ -73,52 +73,59 @@ zn-panel:not(.content-block--short) zn-header::part(header-description) {
|
|
|
73
73
|
display: none;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
counter-
|
|
76
|
+
ol {
|
|
77
|
+
counter-reset: list-0 0;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
@supports (counter-set:none) {
|
|
81
|
-
li
|
|
81
|
+
ol li, ul li {
|
|
82
82
|
counter-set: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
ol, ul {
|
|
87
|
+
padding: 0;
|
|
88
|
+
margin: 0;
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
li[data-list=checked] > .ql-ui
|
|
91
|
-
|
|
91
|
+
li[data-list=checked] > .ql-ui, li[data-list=unchecked] > .ql-ui {
|
|
92
|
+
color: #777;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
li
|
|
95
|
-
|
|
95
|
+
li {
|
|
96
|
+
list-style-type: none;
|
|
97
|
+
padding-left: 1em;
|
|
98
|
+
position: relative;
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
content:
|
|
101
|
+
ul > li::before {
|
|
102
|
+
content: "•";
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
ol {
|
|
103
|
-
|
|
104
|
-
margin: 0;
|
|
105
|
+
ol > li {
|
|
106
|
+
counter-increment: list-0;
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
ol > li::before {
|
|
110
|
+
content: counter(list-0) ". ";
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
/* Checkbox list markers */
|
|
114
|
+
li[data-list="checked"]::before {
|
|
115
|
+
content: "☑";
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
li {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
li[data-list="unchecked"]::before {
|
|
119
|
+
content: "☐";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
li[data-list="checked"]::before,
|
|
123
|
+
li[data-list="unchecked"]::before {
|
|
124
|
+
color: #777;
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
li
|
|
127
|
+
ol li::before,
|
|
128
|
+
ul li::before {
|
|
122
129
|
display: inline-block;
|
|
123
130
|
margin-left: -1.5em;
|
|
124
131
|
margin-right: 0.3em;
|
|
@@ -126,3 +133,8 @@ li > .ql-ui::before {
|
|
|
126
133
|
white-space: nowrap;
|
|
127
134
|
width: 1.2em;
|
|
128
135
|
}
|
|
136
|
+
|
|
137
|
+
li:has(> .ql-ui)::before {
|
|
138
|
+
content: none;
|
|
139
|
+
display: none;
|
|
140
|
+
}
|
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
emptyDataProvider,
|
|
8
8
|
type LocalDataProvider,
|
|
9
9
|
} from "./providers/provider";
|
|
10
|
-
import {type CSSResultGroup, html, nothing,
|
|
10
|
+
import {type CSSResultGroup, html, nothing, type PropertyValues, unsafeCSS} from 'lit';
|
|
11
11
|
import {FormControlController} from "../../internal/form";
|
|
12
12
|
import {property, query} from 'lit/decorators.js';
|
|
13
13
|
import {watch} from "../../internal/watch";
|
|
14
|
-
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
15
14
|
import ZincElement from '../../internal/zinc-element';
|
|
15
|
+
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
16
16
|
import type ZnSelect from "../select";
|
|
17
17
|
|
|
18
18
|
import styles from './data-select.scss';
|
|
@@ -93,6 +93,8 @@ export default class ZnDataSelect extends ZincElement implements ZincFormControl
|
|
|
93
93
|
|
|
94
94
|
@property({attribute: "icon-only", type: Boolean, reflect: true}) iconOnly = false;
|
|
95
95
|
|
|
96
|
+
@property({type: Boolean}) multiple = false;
|
|
97
|
+
|
|
96
98
|
protected readonly formControlController = new FormControlController(this);
|
|
97
99
|
|
|
98
100
|
get validationMessage() {
|
|
@@ -215,6 +217,7 @@ export default class ZnDataSelect extends ZincElement implements ZincFormControl
|
|
|
215
217
|
@zn-clear="${this.handleClear}"
|
|
216
218
|
@blur=${this.blur}
|
|
217
219
|
value="${this.value}"
|
|
220
|
+
?multiple=${this.multiple}
|
|
218
221
|
placeholder="${this.getPlaceholder(localProvider)}"
|
|
219
222
|
exportparts="combobox,expand-icon,form-control-help-text,form-control-input,display-input">
|
|
220
223
|
${(this.iconPosition !== 'none' || this.iconOnly) ? html`
|
|
@@ -92,6 +92,7 @@ interface HeaderConfig {
|
|
|
92
92
|
filterable?: boolean;
|
|
93
93
|
hideHeader?: boolean;
|
|
94
94
|
hideColumn?: boolean;
|
|
95
|
+
secondary?: boolean;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
interface DataRequest {
|
|
@@ -252,7 +253,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
252
253
|
const params: Record<string, any> = {};
|
|
253
254
|
if (inputs) {
|
|
254
255
|
inputs.forEach((input) => {
|
|
255
|
-
const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'input', 'select', 'textarea'];
|
|
256
|
+
const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'zn-datepicker', 'input', 'select', 'textarea'];
|
|
256
257
|
if (allowedInputs.includes(input.tagName.toLowerCase())) {
|
|
257
258
|
const value = (input as AllowedInputElement).value as string || input.getAttribute('value');
|
|
258
259
|
const name = (input as AllowedInputElement).name || input.getAttribute('name');
|
|
@@ -289,6 +290,10 @@ export default class ZnDataTable extends ZincElement {
|
|
|
289
290
|
|
|
290
291
|
private rowHasActions: boolean = false;
|
|
291
292
|
|
|
293
|
+
private _expandedRows: Set<string> = new Set();
|
|
294
|
+
private _hiddenCells: Map<string, Cell[]> = new Map();
|
|
295
|
+
private _secondaryHeaders: HeaderConfig[];
|
|
296
|
+
|
|
292
297
|
requestParams: Record<string, any> = {};
|
|
293
298
|
|
|
294
299
|
refresh() {
|
|
@@ -458,22 +463,40 @@ export default class ZnDataTable extends ZincElement {
|
|
|
458
463
|
}
|
|
459
464
|
|
|
460
465
|
public renderTableData(data: any) {
|
|
466
|
+
// Primary (visible) headers exclude those explicitly hidden and those marked as secondary
|
|
461
467
|
const filteredHeaders = Object.values(this.headers).filter((header: HeaderConfig) => {
|
|
462
|
-
if (header.hideHeader || header.hideColumn)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
468
|
+
if (header.hideHeader || header.hideColumn) return false;
|
|
469
|
+
|
|
470
|
+
if (Object.values(this.hiddenColumns).includes(header.key)) return false;
|
|
471
|
+
|
|
472
|
+
return !header.secondary;
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Secondary headers (shown in expandable details)
|
|
476
|
+
this._secondaryHeaders = Object.values(this.headers).filter((header: HeaderConfig) => {
|
|
477
|
+
if (header.hideColumn) return false;
|
|
478
|
+
|
|
479
|
+
if (Object.values(this.hiddenColumns).includes(header.key)) return false;
|
|
480
|
+
|
|
481
|
+
return header.secondary === true;
|
|
466
482
|
});
|
|
467
483
|
|
|
468
484
|
this.rowHasActions = this._rows.some((row: Row) => row.actions && row.actions.length > 0);
|
|
469
485
|
|
|
470
|
-
//
|
|
486
|
+
// Compute and store hidden cells per row (secondary items only), and reorder visible cells to match header order
|
|
487
|
+
const secondaryKeys = new Set(this._secondaryHeaders.map(h => h.key));
|
|
488
|
+
this._hiddenCells.clear();
|
|
489
|
+
const visibleRowCells: Map<string, Cell[]> = new Map();
|
|
490
|
+
|
|
471
491
|
this._rows.forEach((row: Row) => {
|
|
492
|
+
const originalCells = Array.isArray(row.cells) ? row.cells : [];
|
|
472
493
|
const orderedCells: Cell[] = [];
|
|
473
|
-
|
|
494
|
+
|
|
495
|
+
const hiddenCells = originalCells.filter((c: Cell) => secondaryKeys.has(c.column));
|
|
496
|
+
this._hiddenCells.set(row.id, hiddenCells);
|
|
474
497
|
|
|
475
498
|
filteredHeaders.forEach((header: HeaderConfig) => {
|
|
476
|
-
const cell =
|
|
499
|
+
const cell = originalCells.find((c: Cell) => c.column === header.key);
|
|
477
500
|
if (cell) {
|
|
478
501
|
orderedCells.push(cell);
|
|
479
502
|
} else {
|
|
@@ -481,9 +504,12 @@ export default class ZnDataTable extends ZincElement {
|
|
|
481
504
|
}
|
|
482
505
|
});
|
|
483
506
|
|
|
484
|
-
row.
|
|
507
|
+
visibleRowCells.set(row.id, orderedCells);
|
|
485
508
|
});
|
|
486
509
|
|
|
510
|
+
const anyHidden = this.hasHiddenColumns();
|
|
511
|
+
const colCount = filteredHeaders.length + (this.rowHasActions ? 1 : 0) + (anyHidden ? 1 : 0);
|
|
512
|
+
|
|
487
513
|
return html`
|
|
488
514
|
<div style="overflow-x: auto">
|
|
489
515
|
<table class="${classMap({
|
|
@@ -493,17 +519,27 @@ export default class ZnDataTable extends ZincElement {
|
|
|
493
519
|
})}">
|
|
494
520
|
<thead>
|
|
495
521
|
<tr>
|
|
522
|
+
${anyHidden ? html`
|
|
523
|
+
<th class="table__head table__head--expander"></th>` : nothing}
|
|
496
524
|
${filteredHeaders.map((header: HeaderConfig) => this.renderCellHeader(header))}
|
|
497
525
|
${this.rowHasActions ? html`
|
|
498
526
|
<th></th>` : html``}
|
|
499
527
|
</tr>
|
|
500
528
|
</thead>
|
|
501
529
|
<tbody>
|
|
502
|
-
${data.map((row: Row) => html`
|
|
503
|
-
<tr class="${classMap({
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
530
|
+
${(data as Row[]).map((row: Row, rowIndex: number) => html`
|
|
531
|
+
<tr class="${classMap({
|
|
532
|
+
'table__row--selected': this.isRowSelected(row),
|
|
533
|
+
'table__row--data': true,
|
|
534
|
+
'table__row--even': (rowIndex % 2) === 0,
|
|
535
|
+
'table__row--odd': (rowIndex % 2) === 1,
|
|
536
|
+
})}" data-row-id="${row.id}">
|
|
537
|
+
${anyHidden ? this.renderExpanderCell(row) : nothing}
|
|
538
|
+
${(visibleRowCells.get(row.id) || row.cells).map((value: Cell, index: number) => this.renderCellBody(index, value))}
|
|
539
|
+
${this.rowHasActions ? this.renderActions(row) : nothing}
|
|
540
|
+
</tr>
|
|
541
|
+
${this._expandedRows.has(row.id) ? this.renderDetailsRow(row, colCount) : nothing}
|
|
542
|
+
`)}
|
|
507
543
|
</tbody>
|
|
508
544
|
</table>
|
|
509
545
|
</div>
|
|
@@ -743,7 +779,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
743
779
|
return;
|
|
744
780
|
}
|
|
745
781
|
|
|
746
|
-
const rows = Array.from(this.renderRoot.querySelectorAll('tbody tr'));
|
|
782
|
+
const rows = Array.from(this.renderRoot.querySelectorAll('tbody tr:not([data-details="true"])'));
|
|
747
783
|
const index = rows.indexOf(parent as HTMLTableRowElement);
|
|
748
784
|
if (index === -1) return;
|
|
749
785
|
|
|
@@ -900,15 +936,24 @@ export default class ZnDataTable extends ZincElement {
|
|
|
900
936
|
|
|
901
937
|
private renderCellHeader(header: HeaderConfig) {
|
|
902
938
|
const sortable = !Object.values(this.unsortableHeaders).includes(header.key) && !Object.values(this.hiddenHeaders).includes(header.key) && !this.unsortable;
|
|
903
|
-
|
|
904
|
-
|
|
939
|
+
|
|
940
|
+
// Determine the last visible header considering secondary flags and hidden columns
|
|
941
|
+
const lastVisibleHeaderKey = Object.values(this.headers)
|
|
942
|
+
.filter((h: HeaderConfig) => {
|
|
943
|
+
if (h.hideHeader || h.hideColumn) return false;
|
|
944
|
+
|
|
945
|
+
if (Object.values(this.hiddenColumns).includes(h.key)) return false;
|
|
946
|
+
|
|
947
|
+
return !h.secondary;
|
|
948
|
+
})
|
|
949
|
+
.slice(-1)[0]?.key;
|
|
905
950
|
|
|
906
951
|
return html`
|
|
907
952
|
<th
|
|
908
953
|
class="${classMap({
|
|
909
954
|
'table__head': true,
|
|
910
955
|
'table__head--wide': header.key === this.wideColumn,
|
|
911
|
-
'table__head--last': header.key ===
|
|
956
|
+
'table__head--last': header.key === lastVisibleHeaderKey,
|
|
912
957
|
'table__head--hidden': Object.values(this.hiddenHeaders).includes(header.key),
|
|
913
958
|
})}"
|
|
914
959
|
@click="${sortable ? this.updateSort(header.key) : undefined}">
|
|
@@ -922,16 +967,13 @@ export default class ZnDataTable extends ZincElement {
|
|
|
922
967
|
|
|
923
968
|
private renderCellBody(index: number, value: Cell) {
|
|
924
969
|
const filteredHeaders = Object.values(this.headers).filter((header: HeaderConfig) => {
|
|
925
|
-
if (header.hideHeader || header.hideColumn)
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
return !Object.values(this.hiddenColumns).includes(header.key);
|
|
929
|
-
});
|
|
970
|
+
if (header.hideHeader || header.hideColumn) return false;
|
|
971
|
+
|
|
972
|
+
if (Object.values(this.hiddenColumns).includes(header.key)) return false;
|
|
930
973
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
const headerKey: string = headerKeys[index];
|
|
974
|
+
return !header.secondary;
|
|
975
|
+
});
|
|
976
|
+
const headerKey: string = filteredHeaders[index]?.key;
|
|
935
977
|
|
|
936
978
|
return html`
|
|
937
979
|
<td
|
|
@@ -945,6 +987,65 @@ export default class ZnDataTable extends ZincElement {
|
|
|
945
987
|
</td>`;
|
|
946
988
|
}
|
|
947
989
|
|
|
990
|
+
private hasHiddenColumns(): boolean {
|
|
991
|
+
return this._secondaryHeaders.length > 0;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
private renderExpanderCell(row: Row) {
|
|
995
|
+
const hasHidden = (this._hiddenCells.get(row.id) || []).length > 0;
|
|
996
|
+
if (!hasHidden) return html`
|
|
997
|
+
<td class="table__cell table__cell--expander"></td>`;
|
|
998
|
+
|
|
999
|
+
const expanded = this._expandedRows.has(row.id);
|
|
1000
|
+
const icon = expanded ? 'expand_more' : 'chevron_right';
|
|
1001
|
+
|
|
1002
|
+
return html`
|
|
1003
|
+
<td class="table__cell table__cell--expander">
|
|
1004
|
+
<zn-button
|
|
1005
|
+
color="transparent"
|
|
1006
|
+
size="x-small"
|
|
1007
|
+
icon="${icon}"
|
|
1008
|
+
icon-size="18"
|
|
1009
|
+
aria-label="${expanded ? 'Collapse row' : 'Expand row'}"
|
|
1010
|
+
@click="${(e: Event) => this.toggleRowExpansion(e, row)}">
|
|
1011
|
+
</zn-button>
|
|
1012
|
+
</td>`;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
private renderDetailsRow(row: Row, colSpan: number) {
|
|
1016
|
+
const hiddenCells = this._hiddenCells.get(row.id) || [];
|
|
1017
|
+
if (hiddenCells.length === 0) return html``;
|
|
1018
|
+
|
|
1019
|
+
return html`
|
|
1020
|
+
<tr class="table__row--details" data-details="true">
|
|
1021
|
+
<td colspan="${colSpan}">
|
|
1022
|
+
<div class="table__details">
|
|
1023
|
+
${hiddenCells.map((cell: Cell) => {
|
|
1024
|
+
const header = Object.values(this.headers).find((h: HeaderConfig) => h.key === cell.column);
|
|
1025
|
+
const label = header?.label || this.humanize(cell.column);
|
|
1026
|
+
return html`
|
|
1027
|
+
<div class="table__details__item">
|
|
1028
|
+
<div class="table__details__label">${label}</div>
|
|
1029
|
+
<div class="table__details__value">${this.renderCell(cell)}</div>
|
|
1030
|
+
</div>`;
|
|
1031
|
+
})}
|
|
1032
|
+
</div>
|
|
1033
|
+
</td>
|
|
1034
|
+
</tr>`;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
private toggleRowExpansion(e: Event, row: Row) {
|
|
1038
|
+
e.stopPropagation();
|
|
1039
|
+
|
|
1040
|
+
if (this._expandedRows.has(row.id)) {
|
|
1041
|
+
this._expandedRows.delete(row.id);
|
|
1042
|
+
} else {
|
|
1043
|
+
this._expandedRows.add(row.id);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
this.requestUpdate();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
948
1049
|
private isRowSelected(row: Row): boolean {
|
|
949
1050
|
return this.selectedRows.some((r: Row) => r.id === row.id);
|
|
950
1051
|
}
|