@kubex/zinc 1.0.7 → 1.0.9
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 +411 -83
- package/dist/vscode.html-custom-data.json +45 -16
- package/dist/web-types.json +104 -34
- package/dist/zn.d.ts +57 -3
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +464 -408
- package/docs/data/products-table.json +203 -0
- package/docs/pages/components/button.md +39 -0
- package/docs/pages/components/data-table.md +21 -0
- package/docs/pages/components/header.md +7 -0
- package/docs/pages/components/order-table.md +82 -5
- package/package.json +1 -1
- package/scss/themes/_light.scss +1 -1
- package/src/components/button/button.component.ts +160 -10
- package/src/components/button/button.scss +85 -0
- package/src/components/content-block/content-block.component.ts +18 -7
- package/src/components/content-block/content-block.scss +58 -2
- package/src/components/data-select/data-select.component.ts +0 -1
- package/src/components/data-table/data-table.component.ts +133 -22
- package/src/components/data-table/data-table.scss +14 -3
- package/src/components/editor/editor.scss +1 -1
- package/src/components/expanding-action/expanding-action.component.ts +1 -1
- package/src/components/header/header.component.ts +8 -2
- package/src/components/header/header.scss +5 -1
- package/src/components/linked-select/linked-select.component.ts +1 -0
- package/src/components/menu/menu.component.ts +0 -1
- package/src/components/navbar/navbar.component.ts +1 -1
- package/src/components/note/note.component.ts +70 -2
- package/src/components/note/note.scss +26 -4
- package/src/components/order-table/order-table.component.ts +49 -28
- package/src/components/panel/panel.component.ts +8 -2
- package/src/components/panel/panel.scss +4 -0
- package/src/components/rating/rating.component.ts +10 -9
- package/src/components/rating/rating.scss +15 -1
- package/src/components/settings-container/settings-container.component.ts +1 -1
- package/src/components/tabs/tabs.component.ts +24 -6
- package/src/internal/form.ts +41 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type colors} from "../data-select/providers/color-data-provider";
|
|
3
3
|
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
4
|
-
import {property} from "lit/decorators.js";
|
|
4
|
+
import {property, state} from "lit/decorators.js";
|
|
5
5
|
import ZincElement from '../../internal/zinc-element';
|
|
6
6
|
|
|
7
7
|
import styles from './note.scss';
|
|
@@ -32,6 +32,58 @@ export default class ZnNote extends ZincElement {
|
|
|
32
32
|
@property({reflect: true}) date: string = '';
|
|
33
33
|
@property({type: HTMLElement, reflect: true}) body: string = '';
|
|
34
34
|
|
|
35
|
+
// Number of lines at which the note body collapses; 0 disables collapsing
|
|
36
|
+
@property({type: Number, attribute: 'collapse-at-lines', reflect: true}) collapseAtLines: number = 3;
|
|
37
|
+
|
|
38
|
+
// Internal state: whether the body is currently expanded
|
|
39
|
+
@state() private expanded = false;
|
|
40
|
+
|
|
41
|
+
// Internal state: whether the content actually overflows the clamp
|
|
42
|
+
@state() private _isOverflowing = false;
|
|
43
|
+
|
|
44
|
+
private _toggleExpand = () => {
|
|
45
|
+
this.expanded = !this.expanded;
|
|
46
|
+
// re-evaluate overflow after toggle (in case of dynamic content)
|
|
47
|
+
this.updateComplete.then(() => this._measureOverflow());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private _measureOverflow() {
|
|
51
|
+
// Only relevant when collapseAtLines is set and not expanded
|
|
52
|
+
const container = this.shadowRoot?.querySelector('.note__body-container') as HTMLElement | null;
|
|
53
|
+
if (!container) {
|
|
54
|
+
this._isOverflowing = false;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (this.collapseAtLines <= 0) {
|
|
59
|
+
this._isOverflowing = false;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Temporarily ensure clamped styles are applied to measure
|
|
64
|
+
container.style.setProperty('--note-collapse-lines', String(this.collapseAtLines));
|
|
65
|
+
container.classList.toggle('note__body--clamped', !this.expanded);
|
|
66
|
+
|
|
67
|
+
// element starts hidden, cannot measure
|
|
68
|
+
if (container.clientHeight === 0) {
|
|
69
|
+
this._isOverflowing = false;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Measure overflow
|
|
74
|
+
this._isOverflowing = container.scrollHeight > container.clientHeight + 1; // +1 for rounding errors
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected firstUpdated() {
|
|
78
|
+
// Initial measurement of overflow
|
|
79
|
+
this._measureOverflow();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
protected updated() {
|
|
83
|
+
// Re-measure on any update to catch slot/content changes
|
|
84
|
+
this._measureOverflow();
|
|
85
|
+
}
|
|
86
|
+
|
|
35
87
|
protected render(): unknown {
|
|
36
88
|
return html`
|
|
37
89
|
<div class="${classMap({
|
|
@@ -52,7 +104,23 @@ export default class ZnNote extends ZincElement {
|
|
|
52
104
|
<small>${this.date}</small>
|
|
53
105
|
</slot>
|
|
54
106
|
</div>
|
|
55
|
-
<
|
|
107
|
+
<div class="${classMap({
|
|
108
|
+
'note__body-container': true,
|
|
109
|
+
'note__body--clamped': this.collapseAtLines > 0 && !this.expanded
|
|
110
|
+
})}" style="--note-collapse-lines: ${this.collapseAtLines}">
|
|
111
|
+
<slot class="note__body"></slot>
|
|
112
|
+
</div>
|
|
113
|
+
${this.collapseAtLines > 0 && this._isOverflowing ? html`
|
|
114
|
+
<div class="note__toggle">
|
|
115
|
+
<zn-button color="transparent"
|
|
116
|
+
size="content"
|
|
117
|
+
class="note__toggle__btn"
|
|
118
|
+
@click="${this._toggleExpand}"
|
|
119
|
+
aria-expanded="${String(this.expanded)}">
|
|
120
|
+
${this.expanded ? 'Show less' : 'Show more'}
|
|
121
|
+
</zn-button>
|
|
122
|
+
</div>
|
|
123
|
+
` : ''}
|
|
56
124
|
<slot name="footer" class="note__footer"></slot>
|
|
57
125
|
</div>
|
|
58
126
|
`;
|
|
@@ -42,13 +42,35 @@ $colors: (
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
&__body {
|
|
46
|
-
|
|
47
|
-
flex-direction: column;
|
|
48
|
-
gap: var(--zn-spacing-3x-small);
|
|
45
|
+
&__body-container {
|
|
46
|
+
position: relative;
|
|
49
47
|
max-width: var(--zn-container-md);
|
|
50
48
|
}
|
|
51
49
|
|
|
50
|
+
&__body {
|
|
51
|
+
display: block;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&__body--clamped {
|
|
55
|
+
display: -webkit-box;
|
|
56
|
+
-webkit-box-orient: vertical;
|
|
57
|
+
-webkit-line-clamp: var(--note-collapse-lines, 0);
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__toggle {
|
|
62
|
+
margin-top: var(--zn-spacing-2x-small);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&__toggle__btn {
|
|
66
|
+
background: none;
|
|
67
|
+
border: none;
|
|
68
|
+
color: var(--zn-color-primary-500, currentColor);
|
|
69
|
+
font: inherit;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
padding: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
@each $name, $color in $colors {
|
|
53
75
|
&--#{'' + $name} {
|
|
54
76
|
.note__header__caption {
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
-
import {property} from 'lit/decorators.js';
|
|
2
1
|
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
2
|
+
import {property} from 'lit/decorators.js';
|
|
3
3
|
import ZincElement from '../../internal/zinc-element';
|
|
4
4
|
|
|
5
5
|
import styles from './order-table.scss';
|
|
6
6
|
|
|
7
|
+
interface OrderTableData {
|
|
8
|
+
headers: string[];
|
|
9
|
+
items: {
|
|
10
|
+
caption?: string;
|
|
11
|
+
summary?: string;
|
|
12
|
+
data: string[];
|
|
13
|
+
sub?: {
|
|
14
|
+
caption?: string;
|
|
15
|
+
summary?: string;
|
|
16
|
+
data: string[];
|
|
17
|
+
}[];
|
|
18
|
+
}[];
|
|
19
|
+
tax?: string;
|
|
20
|
+
discount?: string;
|
|
21
|
+
total?: string;
|
|
22
|
+
paid?: string;
|
|
23
|
+
remaining?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
7
26
|
/**
|
|
8
27
|
* @summary Short summary of the component's intended use.
|
|
9
28
|
* @documentation https://zinc.style/components/order-table
|
|
@@ -24,35 +43,23 @@ import styles from './order-table.scss';
|
|
|
24
43
|
export default class ZnOrderTable extends ZincElement {
|
|
25
44
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
26
45
|
|
|
27
|
-
@property({type: Object, reflect: true}) data:
|
|
46
|
+
@property({type: Object, reflect: true}) data: OrderTableData;
|
|
28
47
|
|
|
29
48
|
private isMobile: boolean = false;
|
|
30
|
-
private modifiedData:
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
super();
|
|
34
|
-
this.modifiedData = this.data;
|
|
35
|
-
}
|
|
36
|
-
|
|
49
|
+
private modifiedData: OrderTableData;
|
|
37
50
|
|
|
38
51
|
connectedCallback() {
|
|
39
52
|
this.isMobile = window.innerWidth < 768;
|
|
53
|
+
this.modifiedData = this.data;
|
|
40
54
|
|
|
41
|
-
window.addEventListener('resize',
|
|
42
|
-
if (window.innerWidth < 768 && !this.isMobile) {
|
|
43
|
-
this.isMobile = true;
|
|
44
|
-
this.requestUpdate();
|
|
45
|
-
} else if (window.innerWidth >= 768 && this.isMobile) {
|
|
46
|
-
this.isMobile = false;
|
|
47
|
-
this.requestUpdate();
|
|
48
|
-
}
|
|
49
|
-
});
|
|
55
|
+
window.addEventListener('resize', this.resizeEventHandler);
|
|
50
56
|
|
|
51
57
|
if (this.data === null || this.data === undefined) {
|
|
52
58
|
if (this.childNodes.length > 0 && this.childNodes[0].nodeType === 3) {
|
|
53
|
-
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
const data: ChildNode & { textContent: string } = this.childNodes[0];
|
|
54
61
|
try {
|
|
55
|
-
this.data = JSON.parse(data
|
|
62
|
+
this.data = JSON.parse(data?.textContent) as OrderTableData;
|
|
56
63
|
} catch (e) { /* empty */
|
|
57
64
|
}
|
|
58
65
|
}
|
|
@@ -61,6 +68,20 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
61
68
|
super.connectedCallback();
|
|
62
69
|
}
|
|
63
70
|
|
|
71
|
+
disconnectedCallback() {
|
|
72
|
+
window.removeEventListener('resize', this.resizeEventHandler);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
resizeEventHandler = () => {
|
|
76
|
+
if (window.innerWidth < 768 && !this.isMobile) {
|
|
77
|
+
this.isMobile = true;
|
|
78
|
+
this.requestUpdate();
|
|
79
|
+
} else if (window.innerWidth >= 768 && this.isMobile) {
|
|
80
|
+
this.isMobile = false;
|
|
81
|
+
this.requestUpdate();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
64
85
|
render() {
|
|
65
86
|
this.modifiedData = this.data;
|
|
66
87
|
if (this.isMobile) {
|
|
@@ -107,7 +128,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
107
128
|
const rows = [];
|
|
108
129
|
|
|
109
130
|
|
|
110
|
-
if (data
|
|
131
|
+
if (data?.['items']) {
|
|
111
132
|
for (const item of data['items']) {
|
|
112
133
|
const caption = this.getCaption(item);
|
|
113
134
|
const rowData = item['data'];
|
|
@@ -136,8 +157,8 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
136
157
|
}
|
|
137
158
|
|
|
138
159
|
getCaption(item: any) {
|
|
139
|
-
const caption = item['caption'];
|
|
140
|
-
const summary = item['summary'];
|
|
160
|
+
const caption: string = item['caption'];
|
|
161
|
+
const summary: string = item['summary'];
|
|
141
162
|
|
|
142
163
|
return html`
|
|
143
164
|
<div class="row-item row-caption">
|
|
@@ -184,7 +205,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
184
205
|
|
|
185
206
|
getSummary() {
|
|
186
207
|
let tax = html``;
|
|
187
|
-
if (this.modifiedData
|
|
208
|
+
if (this.modifiedData?.['tax']) {
|
|
188
209
|
tax = html`
|
|
189
210
|
<div class="summary-item">
|
|
190
211
|
<div class="summary-item-title">Tax</div>
|
|
@@ -193,7 +214,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
193
214
|
}
|
|
194
215
|
|
|
195
216
|
let discount = html``;
|
|
196
|
-
if (this.modifiedData
|
|
217
|
+
if (this.modifiedData?.['discount']) {
|
|
197
218
|
discount = html`
|
|
198
219
|
<div class="summary-item">
|
|
199
220
|
<div class="summary-item-title">Discount</div>
|
|
@@ -202,7 +223,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
202
223
|
}
|
|
203
224
|
|
|
204
225
|
let total = html``;
|
|
205
|
-
if (this.modifiedData
|
|
226
|
+
if (this.modifiedData?.['total']) {
|
|
206
227
|
total = html`
|
|
207
228
|
<div class="summary-item">
|
|
208
229
|
<div class="summary-item-title">Grand Total</div>
|
|
@@ -212,7 +233,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
212
233
|
|
|
213
234
|
|
|
214
235
|
let paid = html``;
|
|
215
|
-
if (this.modifiedData
|
|
236
|
+
if (this.modifiedData?.['paid']) {
|
|
216
237
|
paid = html`
|
|
217
238
|
<div class="summary-item">
|
|
218
239
|
<div class="summary-item-title">Amount Paid</div>
|
|
@@ -222,7 +243,7 @@ export default class ZnOrderTable extends ZincElement {
|
|
|
222
243
|
|
|
223
244
|
|
|
224
245
|
let remaining = html``;
|
|
225
|
-
if (this.modifiedData
|
|
246
|
+
if (this.modifiedData?.['remaining']) {
|
|
226
247
|
remaining = html`
|
|
227
248
|
<div class="summary-item">
|
|
228
249
|
<div class="summary-item-title">Amount Outstanding</div>
|
|
@@ -28,8 +28,10 @@ export default class ZnPanel extends ZincElement {
|
|
|
28
28
|
|
|
29
29
|
@property({attribute: 'basis-px', type: Number}) basis: number;
|
|
30
30
|
@property() caption: string;
|
|
31
|
+
@property() icon: string;
|
|
31
32
|
@property() description: string;
|
|
32
33
|
@property({type: Boolean}) tabbed: boolean;
|
|
34
|
+
@property({attribute: 'header-underline', type: Boolean}) underlineHeader: boolean;
|
|
33
35
|
@property({type: Boolean}) cosmic: boolean;
|
|
34
36
|
@property({type: Boolean}) flush: boolean;
|
|
35
37
|
@property({attribute: 'flush-x', type: Boolean}) flushX: boolean;
|
|
@@ -93,9 +95,13 @@ export default class ZnPanel extends ZincElement {
|
|
|
93
95
|
|
|
94
96
|
<div class="panel__inner">
|
|
95
97
|
${hasHeader ? html`
|
|
96
|
-
<zn-header class="
|
|
98
|
+
<zn-header class="${classMap({
|
|
99
|
+
"panel__header": true,
|
|
100
|
+
"panel__header--underline": this.underlineHeader,
|
|
101
|
+
})}"
|
|
102
|
+
icon="${this.icon}"
|
|
97
103
|
caption="${this.caption}"
|
|
98
|
-
description
|
|
104
|
+
description="${ifDefined(this.description)}"
|
|
99
105
|
transparent>
|
|
100
106
|
${hasActionSlot ? html`
|
|
101
107
|
<slot name="actions" slot="actions" class="panel__header__actions"></slot>` : null}
|
|
@@ -54,7 +54,9 @@ export default class ZnRating extends ZincElement implements ZincFormControl {
|
|
|
54
54
|
|
|
55
55
|
@property({type: Boolean}) disabled: boolean = false;
|
|
56
56
|
|
|
57
|
-
@property()
|
|
57
|
+
@property({}) size: 'small' | 'medium' | 'large' = 'medium';
|
|
58
|
+
|
|
59
|
+
@property() getSymbol: (value: number) => string = () => '<zn-icon src="star" library="material"></zn-icon>';
|
|
58
60
|
|
|
59
61
|
/** Gets the validity state object */
|
|
60
62
|
get validity() {
|
|
@@ -170,6 +172,9 @@ export default class ZnRating extends ZincElement implements ZincFormControl {
|
|
|
170
172
|
rating: true,
|
|
171
173
|
'rating--readonly': this.readonly,
|
|
172
174
|
'rating--disabled': this.disabled,
|
|
175
|
+
'rating--small': this.size === 'small',
|
|
176
|
+
'rating--medium': this.size === 'medium',
|
|
177
|
+
'rating--large': this.size === 'large'
|
|
173
178
|
})}"
|
|
174
179
|
role="slider"
|
|
175
180
|
aria-label="${this.label}"
|
|
@@ -196,21 +201,18 @@ export default class ZnRating extends ZincElement implements ZincFormControl {
|
|
|
196
201
|
'rating__partial-symbol-container': true,
|
|
197
202
|
'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1
|
|
198
203
|
})}
|
|
199
|
-
role="presentation"
|
|
200
|
-
>
|
|
204
|
+
role="presentation">
|
|
201
205
|
<div
|
|
202
206
|
style=${styleMap({
|
|
203
207
|
clipPath: `inset(0 0 0 ${(displayValue - index) * 100}%)`
|
|
204
|
-
})}
|
|
205
|
-
>
|
|
208
|
+
})}>
|
|
206
209
|
${unsafeHTML(this.getSymbol(index + 1))}
|
|
207
210
|
</div>
|
|
208
211
|
<div
|
|
209
212
|
class="rating__partial--filled"
|
|
210
213
|
style=${styleMap({
|
|
211
214
|
clipPath: `inset(0 ${100 - (displayValue - index) * 100}% 0 0)`
|
|
212
|
-
})}
|
|
213
|
-
>
|
|
215
|
+
})}>
|
|
214
216
|
${unsafeHTML(this.getSymbol(index + 1))}
|
|
215
217
|
</div>
|
|
216
218
|
</span>
|
|
@@ -223,8 +225,7 @@ export default class ZnRating extends ZincElement implements ZincFormControl {
|
|
|
223
225
|
'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1,
|
|
224
226
|
'rating__symbol--active': displayValue >= index + 1
|
|
225
227
|
})}
|
|
226
|
-
role="presentation"
|
|
227
|
-
>
|
|
228
|
+
role="presentation">
|
|
228
229
|
${unsafeHTML(this.getSymbol(index + 1))}
|
|
229
230
|
</span>`;
|
|
230
231
|
})}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
:host {
|
|
4
4
|
--symbol-color: rgb(var(--zn-border-color));
|
|
5
|
-
--symbol-color-active:
|
|
5
|
+
--symbol-color-active: var(--zn-color-amber-400);
|
|
6
6
|
--symbol-size: 1.2rem;
|
|
7
7
|
--symbol-spacing: 4px;
|
|
8
8
|
|
|
@@ -79,4 +79,18 @@
|
|
|
79
79
|
&--disabled .rating__symbols {
|
|
80
80
|
cursor: not-allowed;
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
&--small {
|
|
84
|
+
--symbol-size: 1rem;
|
|
85
|
+
--symbol-spacing: 2px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&--medium {
|
|
89
|
+
--symbol-size: 1.2rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&--large {
|
|
93
|
+
--symbol-size: 1.5rem;
|
|
94
|
+
--symbol-spacing: 6px;
|
|
95
|
+
}
|
|
82
96
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
3
|
+
import {deepQuerySelectorAll} from "../../utilities/query";
|
|
3
4
|
import {property, state} from "lit/decorators.js";
|
|
4
5
|
import {Store} from "../../internal/storage";
|
|
5
6
|
import {type ZnChangeEvent} from "../../events/zn-change";
|
|
@@ -7,7 +8,6 @@ import ZincElement from '../../internal/zinc-element';
|
|
|
7
8
|
import type ZnCheckbox from "../checkbox";
|
|
8
9
|
|
|
9
10
|
import styles from './settings-container.scss';
|
|
10
|
-
import {deepQuerySelectorAll} from "../../utilities/query";
|
|
11
11
|
|
|
12
12
|
interface SettingsContainerFilter {
|
|
13
13
|
attribute: string;
|
|
@@ -295,7 +295,6 @@ export default class ZnTabs extends ZincElement {
|
|
|
295
295
|
let hasActive = false;
|
|
296
296
|
this._tabs.forEach(tab => {
|
|
297
297
|
|
|
298
|
-
|
|
299
298
|
if (tab.hasAttribute('tab-uri') && this._knownUri.has(tab.getAttribute('tab-uri')!)) {
|
|
300
299
|
tab.setAttribute('tab', this._knownUri.get(tab.getAttribute('tab-uri')!)!);
|
|
301
300
|
}
|
|
@@ -407,19 +406,38 @@ export default class ZnTabs extends ZincElement {
|
|
|
407
406
|
}
|
|
408
407
|
|
|
409
408
|
removeTabAndPanel(tabId: string) {
|
|
410
|
-
if (this.
|
|
411
|
-
this.
|
|
409
|
+
if (this._current === tabId) {
|
|
410
|
+
this.setActiveTab('', true, false);
|
|
412
411
|
}
|
|
413
412
|
|
|
414
413
|
for (const tab of this._tabs) {
|
|
415
414
|
if (tab.getAttribute('tab') === tabId) {
|
|
416
|
-
|
|
415
|
+
|
|
416
|
+
if (tab.hasAttribute('tab-uri')) {
|
|
417
|
+
const tabUri = tab.getAttribute('tab-uri')!;
|
|
418
|
+
if (this._knownUri.has(tabUri)) {
|
|
419
|
+
this._knownUri.delete(tabUri);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
//tab.remove();
|
|
424
|
+
tab.parentElement?.removeChild(tab)
|
|
417
425
|
this._tabs.splice(this._tabs.indexOf(tab), 1);
|
|
418
426
|
}
|
|
419
427
|
}
|
|
420
428
|
|
|
421
|
-
if (this.
|
|
422
|
-
this.
|
|
429
|
+
if (this._panels.has(tabId)) {
|
|
430
|
+
const panel = this._panels.get(tabId);
|
|
431
|
+
if (panel instanceof HTMLElement) {
|
|
432
|
+
panel.remove();
|
|
433
|
+
} else if (panel instanceof Array) {
|
|
434
|
+
panel.forEach((item) => {
|
|
435
|
+
if (item instanceof HTMLElement) {
|
|
436
|
+
item.remove();
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
}
|
|
440
|
+
this._panels.delete(tabId);
|
|
423
441
|
}
|
|
424
442
|
}
|
|
425
443
|
|
package/src/internal/form.ts
CHANGED
|
@@ -235,12 +235,50 @@ export class FormControlController implements ReactiveController {
|
|
|
235
235
|
name.length > 0 &&
|
|
236
236
|
typeof value !== 'undefined'
|
|
237
237
|
) {
|
|
238
|
-
|
|
238
|
+
const appendPrimitive = (val: string | number | boolean) => {
|
|
239
|
+
event.formData.append(name, val.toString());
|
|
240
|
+
};
|
|
241
|
+
const appendFile = (file: Blob, filename?: string) => {
|
|
242
|
+
// If a filename is provided or it's a File (has name), FormData will use it properly
|
|
243
|
+
const maybeFile = file as unknown as File;
|
|
244
|
+
const fname = filename ?? (typeof maybeFile.name === 'string' ? maybeFile.name : undefined);
|
|
245
|
+
// Overloads: append(name, blob, filename?)
|
|
246
|
+
if (typeof fname === 'string') {
|
|
247
|
+
event.formData.append(name, file, fname);
|
|
248
|
+
} else {
|
|
249
|
+
event.formData.append(name, file);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const isFileList = (val: unknown): val is FileList => typeof FileList !== 'undefined' && val instanceof FileList;
|
|
254
|
+
const isBlob = (val: unknown): val is Blob => typeof Blob !== 'undefined' && val instanceof Blob;
|
|
255
|
+
|
|
256
|
+
if (isFileList(value)) {
|
|
257
|
+
// Match native input[type=file] behavior: append each File; if empty, append nothing
|
|
258
|
+
if (value.length > 0) {
|
|
259
|
+
for (let i = 0; i < value.length; i++) {
|
|
260
|
+
const f = value.item(i);
|
|
261
|
+
if (f) appendFile(f, f.name);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} else if (isBlob(value)) {
|
|
265
|
+
appendFile(value, (value as unknown as File).name);
|
|
266
|
+
} else if (Array.isArray(value)) {
|
|
239
267
|
(value as unknown[]).forEach(val => {
|
|
240
|
-
|
|
268
|
+
if (isBlob(val)) {
|
|
269
|
+
appendFile(val as Blob, (val as unknown as File).name);
|
|
270
|
+
} else if (isFileList(val)) {
|
|
271
|
+
const fl = val as FileList;
|
|
272
|
+
for (let i = 0; i < fl.length; i++) {
|
|
273
|
+
const f = fl.item(i);
|
|
274
|
+
if (f) appendFile(f, f.name);
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
appendPrimitive(val as string | number | boolean);
|
|
278
|
+
}
|
|
241
279
|
});
|
|
242
280
|
} else {
|
|
243
|
-
|
|
281
|
+
appendPrimitive(value as string | number | boolean);
|
|
244
282
|
}
|
|
245
283
|
|
|
246
284
|
this.host.dispatchEvent(new CustomEvent('zn-formdata', {bubbles: true, composed: true}));
|