@kubex/zinc 1.1.130 → 1.1.132
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 +117 -1
- package/dist/web-types.json +1 -1
- package/dist/zn.d.ts +5 -0
- package/dist/zn.min.js +66 -66
- package/package.json +1 -1
- package/src/components/panel/panel.component.ts +41 -5
- package/src/components/panel/panel.scss +6 -0
- package/src/components/panel/panel.test.ts +53 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
3
|
import {HasSlotController} from "../../internal/slot";
|
|
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 './panel.scss';
|
|
@@ -43,8 +43,13 @@ export default class ZnPanel extends ZincElement {
|
|
|
43
43
|
@property({type: Boolean}) transparent: boolean;
|
|
44
44
|
@property({type: Boolean}) shadow: boolean;
|
|
45
45
|
|
|
46
|
+
@state() private bodyEmpty = false;
|
|
47
|
+
|
|
48
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
49
|
+
|
|
46
50
|
protected firstUpdated(_changedProperties: PropertyValues) {
|
|
47
51
|
super.firstUpdated(_changedProperties);
|
|
52
|
+
this.observeBodyContent();
|
|
48
53
|
if (this.basis) {
|
|
49
54
|
this.style.setProperty('--zn-panel-basis', this.basis.toString() + 'px');
|
|
50
55
|
}
|
|
@@ -63,6 +68,10 @@ export default class ZnPanel extends ZincElement {
|
|
|
63
68
|
|
|
64
69
|
connectedCallback() {
|
|
65
70
|
super.connectedCallback();
|
|
71
|
+
if (this.hasUpdated) {
|
|
72
|
+
this.observeBodyContent();
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
if (window.CSS.registerProperty) {
|
|
67
76
|
try {
|
|
68
77
|
window.CSS.registerProperty({
|
|
@@ -77,14 +86,40 @@ export default class ZnPanel extends ZincElement {
|
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
|
|
89
|
+
disconnectedCallback() {
|
|
90
|
+
super.disconnectedCallback();
|
|
91
|
+
this.resizeObserver?.disconnect();
|
|
92
|
+
this.resizeObserver = null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private observeBodyContent() {
|
|
96
|
+
const body = this.renderRoot?.querySelector('.panel__body');
|
|
97
|
+
if (!body) return;
|
|
98
|
+
|
|
99
|
+
this.resizeObserver ??= new ResizeObserver(() => this.measureBodyContent());
|
|
100
|
+
this.resizeObserver.disconnect();
|
|
101
|
+
this.resizeObserver.observe(body);
|
|
102
|
+
this.measureBodyContent();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Measured on the body, not on the slotted elements: `display: contents` hosts such as zn-stat
|
|
106
|
+
// render content but have no box of their own to read or observe.
|
|
107
|
+
private measureBodyContent() {
|
|
108
|
+
const body = this.renderRoot?.querySelector('.panel__body');
|
|
109
|
+
if (!body) return;
|
|
110
|
+
|
|
111
|
+
const style = getComputedStyle(body);
|
|
112
|
+
const padding = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
|
|
113
|
+
this.bodyEmpty = body.scrollHeight - padding <= 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
80
116
|
protected render(): unknown {
|
|
81
117
|
const hasActionSlot = this.hasSlotController.test('actions');
|
|
82
118
|
const hasFooterSlot = this.hasSlotController.test('footer');
|
|
83
119
|
const hasHeader = this.caption || hasActionSlot;
|
|
84
|
-
|
|
85
|
-
// so the underline is just a stray rule across the page.
|
|
120
|
+
const isBodyEmpty = !this.hasSlotController.test('[default]') || this.bodyEmpty;
|
|
86
121
|
const isFlushY = this.flush || this.tabbed || this.flushY;
|
|
87
|
-
const underlineHeader = !this.headerBorderless && !(this.transparent && isFlushY);
|
|
122
|
+
const underlineHeader = !this.headerBorderless && !(this.transparent && isFlushY) && !isBodyEmpty;
|
|
88
123
|
|
|
89
124
|
return html`
|
|
90
125
|
<div class="${classMap({
|
|
@@ -97,6 +132,7 @@ export default class ZnPanel extends ZincElement {
|
|
|
97
132
|
'panel--transparent': this.transparent,
|
|
98
133
|
'panel--has-actions': hasActionSlot,
|
|
99
134
|
'panel--has-footer': hasFooterSlot,
|
|
135
|
+
'panel--empty': isBodyEmpty,
|
|
100
136
|
'panel--has-header': hasHeader,
|
|
101
137
|
'panel--borderless-header': this.headerBorderless,
|
|
102
138
|
'panel--cosmic': this.cosmic,
|
|
@@ -120,7 +156,7 @@ export default class ZnPanel extends ZincElement {
|
|
|
120
156
|
|
|
121
157
|
<div class="panel__content">
|
|
122
158
|
<div class="panel__body">
|
|
123
|
-
<slot></slot>
|
|
159
|
+
<slot @slotchange="${this.observeBodyContent}"></slot>
|
|
124
160
|
</div>
|
|
125
161
|
</div>
|
|
126
162
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
|
+
import { aTimeout, expect, fixture, html, waitUntil } from '@open-wc/testing';
|
|
3
3
|
|
|
4
4
|
describe('<zn-panel>', () => {
|
|
5
5
|
it('should render a component', async () => {
|
|
@@ -9,16 +9,66 @@ describe('<zn-panel>', () => {
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('underlines panel headers by default', async () => {
|
|
12
|
-
const el = await fixture(html` <zn-panel caption="Example"></zn-panel> `);
|
|
12
|
+
const el = await fixture(html` <zn-panel caption="Example"><p>Content</p></zn-panel> `);
|
|
13
13
|
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
14
14
|
|
|
15
15
|
expect(header.classList.contains('panel__header--underline')).to.be.true;
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
it('removes the header underline when header-borderless is set', async () => {
|
|
19
|
-
const el = await fixture(html` <zn-panel caption="Example" header-borderless></zn-panel> `);
|
|
19
|
+
const el = await fixture(html` <zn-panel caption="Example" header-borderless><p>Content</p></zn-panel> `);
|
|
20
|
+
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
21
|
+
|
|
22
|
+
expect(header.classList.contains('panel__header--underline')).to.be.false;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('removes the header underline and body padding when there is no content', async () => {
|
|
26
|
+
const el = await fixture(html` <zn-panel caption="Example"></zn-panel> `);
|
|
20
27
|
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
21
28
|
|
|
22
29
|
expect(header.classList.contains('panel__header--underline')).to.be.false;
|
|
30
|
+
expect(el.shadowRoot!.querySelector('.panel')!.classList.contains('panel--empty')).to.be.true;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('removes the header underline when slotted content renders nothing', async () => {
|
|
34
|
+
const el = await fixture(html` <zn-panel caption="Example">
|
|
35
|
+
<div id="wrapper"></div>
|
|
36
|
+
</zn-panel> `);
|
|
37
|
+
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
38
|
+
|
|
39
|
+
await waitUntil(() => !header.classList.contains('panel__header--underline'));
|
|
40
|
+
|
|
41
|
+
expect(el.shadowRoot!.querySelector('.panel')!.classList.contains('panel--empty')).to.be.true;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('keeps the padded body when slotted content has no box of its own', async () => {
|
|
45
|
+
const el = await fixture(html` <zn-panel caption="Example">
|
|
46
|
+
<div style="display: contents">
|
|
47
|
+
<div style="height: 20px"></div>
|
|
48
|
+
</div>
|
|
49
|
+
</zn-panel> `);
|
|
50
|
+
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
51
|
+
|
|
52
|
+
await aTimeout(50);
|
|
53
|
+
|
|
54
|
+
expect(header.classList.contains('panel__header--underline')).to.be.true;
|
|
55
|
+
expect(el.shadowRoot!.querySelector('.panel')!.classList.contains('panel--empty')).to.be.false;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('restores the header underline when slotted content gains height', async () => {
|
|
59
|
+
const el = await fixture(html` <zn-panel caption="Example">
|
|
60
|
+
<div id="wrapper"></div>
|
|
61
|
+
</zn-panel> `);
|
|
62
|
+
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
63
|
+
|
|
64
|
+
await waitUntil(() => !header.classList.contains('panel__header--underline'));
|
|
65
|
+
|
|
66
|
+
const child = document.createElement('div');
|
|
67
|
+
child.style.height = '20px';
|
|
68
|
+
el.querySelector('#wrapper')!.append(child);
|
|
69
|
+
|
|
70
|
+
await waitUntil(() => header.classList.contains('panel__header--underline'));
|
|
71
|
+
|
|
72
|
+
expect(el.shadowRoot!.querySelector('.panel')!.classList.contains('panel--empty')).to.be.false;
|
|
23
73
|
});
|
|
24
74
|
});
|