@kubex/zinc 1.1.121 → 1.1.123

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.
Files changed (37) hide show
  1. package/dist/custom-elements.json +2847 -1816
  2. package/dist/vscode.html-custom-data.json +189 -167
  3. package/dist/web-types.json +531 -465
  4. package/dist/zn.d.ts +401 -296
  5. package/dist/zn.min.js +1478 -1337
  6. package/docs/pages/components/button.md +9 -0
  7. package/docs/pages/components/data-table-filter.md +60 -4
  8. package/docs/pages/components/data-table-search.md +3 -3
  9. package/docs/pages/components/data-table.md +78 -9
  10. package/docs/pages/components/datepicker.md +10 -0
  11. package/docs/pages/components/menu-item.md +16 -2
  12. package/package.json +1 -1
  13. package/src/components/button/button.component.ts +11 -4
  14. package/src/components/button/button.scss +12 -1
  15. package/src/components/data-table/data-table.component.ts +341 -139
  16. package/src/components/data-table/data-table.scss +110 -43
  17. package/src/components/data-table/data-table.test.ts +110 -0
  18. package/src/components/data-table-filter/data-table-filter.component.ts +487 -49
  19. package/src/components/data-table-filter/data-table-filter.scss +163 -9
  20. package/src/components/data-table-filter/data-table-filter.test.ts +328 -2
  21. package/src/components/data-table-search/data-table-search.component.ts +1 -1
  22. package/src/components/data-table-search/data-table-search.scss +5 -0
  23. package/src/components/datepicker/datepicker.component.ts +23 -2
  24. package/src/components/datepicker/datepicker.scss +25 -0
  25. package/src/components/datepicker/datepicker.test.ts +28 -1
  26. package/src/components/input/input.component.ts +1 -0
  27. package/src/components/input/input.scss +1 -1
  28. package/src/components/menu/menu.component.ts +2 -0
  29. package/src/components/menu/menu.scss +23 -2
  30. package/src/components/menu-item/menu-item.component.ts +7 -1
  31. package/src/components/menu-item/menu-item.scss +4 -4
  32. package/src/components/menu-item/menu-item.test.ts +39 -1
  33. package/src/components/panel/panel.component.ts +12 -5
  34. package/src/components/panel/panel.scss +3 -3
  35. package/src/components/query-builder/query-builder.component.ts +1 -1
  36. package/src/components/tooltip/tooltip.component.ts +2 -2
  37. package/src/components/tooltip/tooltip.test.ts +70 -2
@@ -1,5 +1,5 @@
1
1
  import '../../../dist/zn.min.js';
2
- import {expect, fixture, html} from '@open-wc/testing';
2
+ import {expect, fixture, html, waitUntil} from '@open-wc/testing';
3
3
  import type ZnDatepicker from './datepicker.component';
4
4
 
5
5
  describe('<zn-datepicker>', () => {
@@ -9,6 +9,33 @@ describe('<zn-datepicker>', () => {
9
9
  expect(el).to.exist;
10
10
  });
11
11
 
12
+ describe('inline', () => {
13
+ it('renders the calendar in place and hides the text input', async () => {
14
+ const el = await fixture<ZnDatepicker>(html`<zn-datepicker inline></zn-datepicker>`);
15
+ await el.updateComplete;
16
+
17
+ const calendar = el.shadowRoot!.querySelector('.air-datepicker');
18
+
19
+ expect(calendar, 'calendar should live in the datepicker shadow root').to.exist;
20
+ expect(calendar!.classList.contains('-inline-')).to.be.true;
21
+ expect(getComputedStyle(el.input).display).to.equal('none');
22
+ });
23
+
24
+ it('emits zn-change when a day is picked', async () => {
25
+ const el = await fixture<ZnDatepicker>(html`<zn-datepicker inline></zn-datepicker>`);
26
+ await el.updateComplete;
27
+
28
+ let emitted = 0;
29
+ el.addEventListener('zn-change', () => emitted++);
30
+
31
+ const day = el.shadowRoot!.querySelector<HTMLElement>('.air-datepicker-cell.-day-:not(.-other-month-)')!;
32
+ day.click();
33
+ await waitUntil(() => emitted > 0);
34
+
35
+ expect(el.value).to.not.equal('');
36
+ });
37
+ });
38
+
12
39
  describe('Escape key', () => {
13
40
  it('blurs the inner input when focused and the calendar is closed', async () => {
14
41
  const el = await fixture<ZnDatepicker>(html`<zn-datepicker></zn-datepicker>`);
@@ -68,6 +68,7 @@ import styles from './input.scss';
68
68
  * @csspart password-toggle-button - The password toggle button.
69
69
  * @csspart suffix - The container that wraps the suffix.
70
70
  *
71
+ * @cssproperty --zn-input-box-shadow - Shadow cast by the field; set to `none` inside a panel that draws its own edge.
71
72
  * @cssproperty --zn-range-track-height - The height of a range input's track.
72
73
  * @cssproperty --zn-range-track-color - The color of a range input's track.
73
74
  * @cssproperty --zn-range-thumb-size - The diameter of a range input's thumb.
@@ -11,7 +11,7 @@
11
11
  justify-content: start;
12
12
  position: relative;
13
13
  width: 100%;
14
- box-shadow: var(--zn-shadow-x-small);
14
+ box-shadow: var(--zn-input-box-shadow, var(--zn-shadow-x-small));
15
15
  font-family: var(--zn-input-font-family), sans-serif;
16
16
  font-weight: var(--zn-input-font-weight);
17
17
  letter-spacing: var(--zn-input-letter-spacing);
@@ -46,6 +46,8 @@ interface NavItem {
46
46
  * @cssproperty --example - An example CSS custom property.
47
47
  * @cssproperty --zn-menu-max-height - Caps the menu's height and makes it scroll internally.
48
48
  * Unset (`none`) by default, so the menu grows to fit its items unless a consumer sets this.
49
+ * @cssproperty --zn-menu-min-width - Overrides the menu's resting width. Defaults to
50
+ * `--zn-size-spanel`, or 245px for `variant="shell"`.
49
51
  */
50
52
  export default class ZnMenu extends ZincElement {
51
53
  static styles: CSSResultGroup = unsafeCSS(styles);
@@ -7,7 +7,7 @@
7
7
  border: 1px solid rgb(var(--zn-border-color)) !important;
8
8
  border-radius: var(--zn-border-radius);
9
9
  width: fit-content;
10
- min-width: var(--zn-size-spanel);
10
+ min-width: var(--zn-menu-min-width, var(--zn-size-spanel));
11
11
  // Unconstrained by default — a consumer that needs the menu to scroll inside a bounded
12
12
  // popup (rather than growing to fit all its items) sets this custom property.
13
13
  max-height: var(--zn-menu-max-height, none);
@@ -22,6 +22,26 @@
22
22
  background-color: rgba(var(--zn-color-navigation, 255, 255, 255), 0.95);
23
23
  }
24
24
 
25
+ // A capped menu has to look scrollable, so the bar is always drawn rather than
26
+ // left to the platform's overlay scrollbar
27
+ .menu {
28
+ &::-webkit-scrollbar {
29
+ width: 10px;
30
+ }
31
+
32
+ &::-webkit-scrollbar-thumb {
33
+ border: 3px solid transparent;
34
+ border-radius: 5px;
35
+ background: rgba(var(--inverse-base), 0.3);
36
+ background-clip: content-box;
37
+ }
38
+
39
+ &::-webkit-scrollbar-thumb:hover {
40
+ background: rgba(var(--inverse-base), 0.5);
41
+ background-clip: content-box;
42
+ }
43
+ }
44
+
25
45
  // Dropdown vs shell hover/row styling lives on zn-menu-item, keyed by the
26
46
  // `variant` the menu sets on its items (see menu.component.ts).
27
47
 
@@ -34,8 +54,9 @@
34
54
  padding: var(--zn-spacing-2x-small);
35
55
  border: 1px solid rgb(var(--zn-border-color));
36
56
  border-radius: var(--zn-border-radius);
37
- min-width: 245px;
57
+ min-width: var(--zn-menu-min-width, 245px);
38
58
  max-width: min(320px, calc(100vw - 16px));
59
+ max-height: var(--zn-menu-max-height, none);
39
60
  overflow-x: hidden;
40
61
  overflow-y: auto;
41
62
  box-shadow: none;
@@ -82,6 +82,9 @@ export default class ZnMenuItem extends ZincElement {
82
82
 
83
83
  @property({type: Boolean, reflect: true}) confirm = false;
84
84
 
85
+ /** Leaves a containing dropdown open when this item is selected, whatever the dropdown's own setting. */
86
+ @property({type: Boolean, reflect: true, attribute: 'keep-open'}) keepOpen = false;
87
+
85
88
  /** Removes all padding from the menu item. */
86
89
  @property({type: Boolean, reflect: true}) flush = false;
87
90
 
@@ -141,7 +144,10 @@ export default class ZnMenuItem extends ZincElement {
141
144
  const closestMenu: Element | null = composedPath.find((el: Element) => el?.getAttribute?.('role') === 'menu') as Element;
142
145
  if (this.confirm) return;
143
146
 
144
- (closestMenu?.closest('zn-dropdown') as ZnDropdown | null)?.hide();
147
+ const dropdown = closestMenu?.closest('zn-dropdown') as ZnDropdown | null;
148
+ if (!dropdown?.stayOpenOnSelect && !this.keepOpen) {
149
+ dropdown?.hide();
150
+ }
145
151
  this.emit('zn-menu-select', {detail: {value: this.value, element: this}});
146
152
  }
147
153
  };
@@ -154,7 +154,7 @@
154
154
  color: var(--color);
155
155
  }
156
156
 
157
- .menu-item:hover .menu-item__label {
157
+ .menu-item:hover:not(.menu-item--disabled) .menu-item__label {
158
158
  color: var(--hover-color);
159
159
  }
160
160
 
@@ -194,9 +194,9 @@
194
194
  bottom: 0;
195
195
  left: 0;
196
196
  clip-path: polygon(
197
- var(--safe-triangle-cursor-x, 0) var(--safe-triangle-cursor-y, 0),
198
- var(--safe-triangle-submenu-start-x, 0) var(--safe-triangle-submenu-start-y, 0),
199
- var(--safe-triangle-submenu-end-x, 0) var(--safe-triangle-submenu-end-y, 0)
197
+ var(--safe-triangle-cursor-x, 0) var(--safe-triangle-cursor-y, 0),
198
+ var(--safe-triangle-submenu-start-x, 0) var(--safe-triangle-submenu-start-y, 0),
199
+ var(--safe-triangle-submenu-end-x, 0) var(--safe-triangle-submenu-end-y, 0)
200
200
  );
201
201
  }
202
202
 
@@ -1,5 +1,6 @@
1
1
  import '../../../dist/zn.min.js';
2
- import { expect, fixture, html } from '@open-wc/testing';
2
+ import {expect, fixture, html, waitUntil} from '@open-wc/testing';
3
+ import type ZnDropdown from '../dropdown/dropdown.component';
3
4
 
4
5
  describe('<zn-menu-item>', () => {
5
6
  it('should render a component', async () => {
@@ -7,4 +8,41 @@ describe('<zn-menu-item>', () => {
7
8
 
8
9
  expect(el).to.exist;
9
10
  });
11
+
12
+ describe('keep-open', () => {
13
+ async function dropdownWithItems() {
14
+ const el = await fixture<ZnDropdown>(html`
15
+ <zn-dropdown>
16
+ <zn-button slot="trigger">Open</zn-button>
17
+ <zn-menu>
18
+ <zn-menu-item value="keeper" keep-open>Keeper</zn-menu-item>
19
+ <zn-menu-item value="closer">Closer</zn-menu-item>
20
+ </zn-menu>
21
+ </zn-dropdown>`);
22
+ await el.updateComplete;
23
+ await el.show();
24
+ return el;
25
+ }
26
+
27
+ const clickOn = (el: Element | null) =>
28
+ el?.dispatchEvent(new MouseEvent('click', {bubbles: true, composed: true, cancelable: true}));
29
+
30
+ it('leaves the dropdown open when the item is selected', async () => {
31
+ const dropdown = await dropdownWithItems();
32
+
33
+ clickOn(dropdown.querySelector('zn-menu-item[value="keeper"]'));
34
+ await dropdown.updateComplete;
35
+
36
+ expect(dropdown.open).to.be.true;
37
+ });
38
+
39
+ it('does not affect the items beside it', async () => {
40
+ const dropdown = await dropdownWithItems();
41
+
42
+ clickOn(dropdown.querySelector('zn-menu-item[value="closer"]'));
43
+
44
+ await waitUntil(() => !dropdown.open);
45
+ expect(dropdown.open).to.be.false;
46
+ });
47
+ });
10
48
  });
@@ -17,8 +17,13 @@ import styles from './panel.scss';
17
17
  * @slot footer - Content displayed in the panel footer.
18
18
  *
19
19
  * @csspart base - The component's base wrapper.
20
+ * @csspart header - The header region, when a caption or actions are given.
21
+ * @csspart header-content - The padded row inside the header, forwarded from zn-header.
22
+ * @csspart footer - The footer region, when the footer slot is filled.
20
23
  *
21
24
  * @cssproperty --zn-panel-basis - The flex-basis of the panel. Can be set using the basis-px attribute.
25
+ * @cssproperty --zn-panel-header-padding - Padding around the header row. Defaults to `--zn-base-gap`.
26
+ * @cssproperty --zn-panel-footer-padding - Padding around the footer row.
22
27
  */
23
28
  export default class ZnPanel extends ZincElement {
24
29
  static styles: CSSResultGroup = unsafeCSS(styles);
@@ -100,10 +105,12 @@ export default class ZnPanel extends ZincElement {
100
105
 
101
106
  <div class="panel__inner">
102
107
  ${hasHeader ? html`
103
- <zn-header class="${classMap({
104
- "panel__header": true,
105
- "panel__header--underline": underlineHeader,
106
- })}"
108
+ <zn-header part="header"
109
+ exportparts="content:header-content"
110
+ class="${classMap({
111
+ "panel__header": true,
112
+ "panel__header--underline": underlineHeader,
113
+ })}"
107
114
  icon="${this.icon}"
108
115
  caption="${this.caption}"
109
116
  transparent>
@@ -118,7 +125,7 @@ export default class ZnPanel extends ZincElement {
118
125
  </div>
119
126
 
120
127
  ${hasFooterSlot ? html`
121
- <slot name="footer" class="panel__footer"></slot>` : null}
128
+ <slot name="footer" part="footer" class="panel__footer"></slot>` : null}
122
129
  </div>
123
130
  </div>`;
124
131
  }
@@ -43,7 +43,7 @@
43
43
 
44
44
 
45
45
  &__header {
46
- padding: var(--zn-base-gap);
46
+ padding: var(--zn-panel-header-padding, var(--zn-base-gap));
47
47
 
48
48
  // background-color: rgba(var(--zn-panel-highlight), 0.6);
49
49
  // border-bottom: 1px solid rgb(var(--zn-border-color));
@@ -81,8 +81,8 @@
81
81
  &__footer {
82
82
  font-size: var(--zn-font-size-small);
83
83
  display: block;
84
- padding: var(--zn-spacing-small) var(--zn-base-gap);
85
- background: rgb(var(--zn-panel-secondary));
84
+ padding: var(--zn-panel-footer-padding, var(--zn-spacing-small) var(--zn-base-gap));
85
+ background: rgb(var(--zn-body));
86
86
  border-bottom-left-radius: var(--zn-border-radius);
87
87
  border-bottom-right-radius: var(--zn-border-radius);
88
88
  }
@@ -80,7 +80,7 @@ export enum QueryBuilderOperators {
80
80
  Lte = 'lte'
81
81
  }
82
82
 
83
- const operatorText: { [key in QueryBuilderOperators]: string } = {
83
+ export const operatorText: { [key in QueryBuilderOperators]: string } = {
84
84
  [QueryBuilderOperators.Eq]: 'Equals',
85
85
  [QueryBuilderOperators.Neq]: 'Not Equals',
86
86
  [QueryBuilderOperators.Eqi]: 'Equals (Insensitive)',
@@ -83,7 +83,7 @@ export default class ZnTooltip extends ZincElement {
83
83
  }
84
84
 
85
85
  private handleBlur = () => {
86
- if (this.hasTrigger('focus') && !topLayerManager.isDropdownOpen()) {
86
+ if (this.hasTrigger('focus')) {
87
87
  this.hide();
88
88
  }
89
89
  };
@@ -118,7 +118,7 @@ export default class ZnTooltip extends ZincElement {
118
118
  }
119
119
 
120
120
  private handleMouseOut() {
121
- if (this.hasTrigger('hover') && !topLayerManager.isDropdownOpen()) {
121
+ if (this.hasTrigger('hover')) {
122
122
  clearTimeout(this.hoverTimeout);
123
123
  this.hoverTimeout = window.setTimeout(() => this.hide(), 0);
124
124
  }
@@ -1,10 +1,78 @@
1
1
  import '../../../dist/zn.min.js';
2
- import { expect, fixture, html } from '@open-wc/testing';
2
+ import {expect, fixture, html, waitUntil} from '@open-wc/testing';
3
+ import type ZnDropdown from '../dropdown/dropdown.component';
4
+ import type ZnTooltip from './tooltip.component';
5
+
6
+ const mouse = (el: Element, type: string) =>
7
+ el.dispatchEvent(new MouseEvent(type, {bubbles: true, composed: true, cancelable: true}));
3
8
 
4
9
  describe('<zn-tooltip>', () => {
5
10
  it('should render a component', async () => {
6
- const el = await fixture(html` <zn-tooltip></zn-tooltip> `);
11
+ const el = await fixture(html`
12
+ <zn-tooltip></zn-tooltip>`);
7
13
 
8
14
  expect(el).to.exist;
9
15
  });
16
+
17
+ it('hides on mouseout', async () => {
18
+ const el = await fixture<ZnTooltip>(html`
19
+ <zn-tooltip content="Columns">
20
+ <button>Trigger</button>
21
+ </zn-tooltip>`);
22
+
23
+ mouse(el, 'mouseover');
24
+ await waitUntil(() => el.open);
25
+
26
+ mouse(el, 'mouseout');
27
+ await waitUntil(() => !el.open);
28
+
29
+ expect(el.open).to.be.false;
30
+ });
31
+
32
+ // A tooltip whose trigger opens a dropdown loses its chance to hide: the pointer
33
+ // leaves the trigger for the menu while the dropdown is registered as open.
34
+ it('hides on mouseout while a dropdown is open', async () => {
35
+ const dropdown = await fixture<ZnDropdown>(html`
36
+ <zn-dropdown>
37
+ <zn-button slot="trigger" tooltip="Columns"></zn-button>
38
+ <zn-menu>
39
+ <zn-menu-item value="a">Alpha</zn-menu-item>
40
+ </zn-menu>
41
+ </zn-dropdown>`);
42
+
43
+ const trigger = dropdown.querySelector('zn-button')!;
44
+ await trigger.updateComplete;
45
+ const tooltip = trigger.shadowRoot!.querySelector('zn-tooltip')!;
46
+
47
+ mouse(tooltip, 'mouseover');
48
+ await waitUntil(() => tooltip.open);
49
+
50
+ await dropdown.show();
51
+ mouse(tooltip, 'mouseout');
52
+ await dropdown.hide();
53
+
54
+ await waitUntil(() => !tooltip.open, 'tooltip stayed open after the dropdown closed');
55
+ expect(tooltip.open).to.be.false;
56
+ });
57
+
58
+ it('does not show while a dropdown is open', async () => {
59
+ const dropdown = await fixture<ZnDropdown>(html`
60
+ <zn-dropdown>
61
+ <zn-button slot="trigger" tooltip="Columns"></zn-button>
62
+ <zn-menu>
63
+ <zn-menu-item value="a">Alpha</zn-menu-item>
64
+ </zn-menu>
65
+ </zn-dropdown>`);
66
+
67
+ const trigger = dropdown.querySelector('zn-button')!;
68
+ await trigger.updateComplete;
69
+ const tooltip = trigger.shadowRoot!.querySelector('zn-tooltip')!;
70
+
71
+ await dropdown.show();
72
+ mouse(tooltip, 'mouseover');
73
+ await new Promise(resolve => setTimeout(resolve, 50));
74
+
75
+ expect(tooltip.open).to.be.false;
76
+ await dropdown.hide();
77
+ });
10
78
  });