@kubex/zinc 2.0.2 → 2.0.4
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 +356 -115
- package/dist/vscode.html-custom-data.json +29 -14
- package/dist/web-types.json +67 -45
- package/dist/zn.d.ts +47 -21
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +333 -309
- package/docs/pages/components/form-actions.md +11 -0
- package/package.json +1 -1
- package/scss/_global-spacing.scss +7 -0
- package/scss/_root.scss +1 -5
- package/src/components/button/button.component.ts +2 -2
- package/src/components/button/button.test.ts +7 -0
- package/src/components/chart/chart.component.ts +1 -1
- package/src/components/editor/modules/dialog/dialog.test.ts +1 -1
- package/src/components/expanding-action/expanding-action.component.ts +1 -1
- package/src/components/filter-wrapper/filter-wrapper.component.ts +1 -1
- package/src/components/form-actions/form-actions.component.ts +112 -14
- package/src/components/form-actions/form-actions.scss +37 -1
- package/src/components/form-actions/form-actions.test.ts +137 -0
- package/src/components/inline-edit/inline-edit.component.ts +1 -2
- package/src/components/inline-edit/inline-edit.scss +20 -20
- package/src/components/input/input.component.ts +38 -2
- package/src/components/input/input.scss +96 -33
- package/src/components/input/input.test.ts +1 -1
- package/src/components/key-value/key-value.component.ts +123 -12
- package/src/components/key-value/key-value.scss +13 -0
- package/src/components/key-value/key-value.test.ts +65 -2
- package/src/components/nav-list/nav-list.test.ts +1 -1
- package/src/components/navbar/navbar.component.ts +14 -8
- package/src/components/panel/panel.component.ts +1 -1
- package/src/components/priority-list/priority-list.test.ts +1 -1
- package/src/components/select/select.test.ts +24 -0
- package/src/components/split-pane/split-pane.component.ts +1 -1
- package/src/components/table/table.component.ts +5 -2
- package/src/components/table/table.scss +4 -0
- package/src/components/table/table.test.ts +13 -0
- package/src/components/tabs/tabs.component.ts +2 -2
- package/src/internal/conditional.ts +9 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
3
|
import {ifDefined} from "lit/directives/if-defined.js";
|
|
4
|
+
import {type IndicatorEdges, slideTabIndicator, squishTabIndicator} from "../../internal/tab-indicator";
|
|
4
5
|
import {MutationController} from '@lit-labs/observers/mutation-controller.js';
|
|
5
6
|
import {property} from 'lit/decorators.js';
|
|
6
7
|
import {ResizeController} from '@lit-labs/observers/resize-controller.js';
|
|
7
|
-
import {type IndicatorEdges, slideTabIndicator, squishTabIndicator} from "../../internal/tab-indicator";
|
|
8
8
|
import {Store} from "../../internal/storage";
|
|
9
9
|
import ZincElement from '../../internal/zinc-element';
|
|
10
10
|
import ZnDropdown from "../dropdown";
|
|
@@ -111,6 +111,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
111
111
|
private _indicator: HTMLElement | null = null;
|
|
112
112
|
private _indicatorFrame: number | null = null;
|
|
113
113
|
private _indicatorTab: HTMLElement | null = null;
|
|
114
|
+
private _indicatorStripWidth = 0;
|
|
114
115
|
private _indicatorTarget: IndicatorEdges | null = null;
|
|
115
116
|
private _expandable: HTMLElement | null = null;
|
|
116
117
|
private readonly _lightDomClones = new WeakMap<HTMLElement, HTMLElement>();
|
|
@@ -242,18 +243,23 @@ export default class ZnNavbar extends ZincElement {
|
|
|
242
243
|
|
|
243
244
|
// The indicator scrolls with the tabs, so it is placed in the strip's content coordinates
|
|
244
245
|
const box = container.getBoundingClientRect();
|
|
245
|
-
|
|
246
|
-
const
|
|
246
|
+
// An ancestor mid scale-in (e.g. a modal opening) shrinks every rect, and its end fires no resize to re-measure
|
|
247
|
+
const scaleX = box.width / container.offsetWidth || 1;
|
|
248
|
+
const scaleY = box.height / container.offsetHeight || 1;
|
|
249
|
+
const toStrip = (x: number) => (x - box.left) / scaleX + container.scrollLeft;
|
|
250
|
+
const target = {left: toStrip(tab.left), right: toStrip(tab.right)};
|
|
247
251
|
const previous = this._indicatorTarget;
|
|
248
252
|
const tabChanged = active !== this._indicatorTab;
|
|
249
253
|
const ready = indicator.classList.contains('navbar__indicator--ready');
|
|
250
254
|
this._indicatorTab = active ?? null;
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
const stripResized = container.clientWidth !== this._indicatorStripWidth;
|
|
256
|
+
this._indicatorStripWidth = container.clientWidth;
|
|
257
|
+
if (active && (tabChanged || stripResized)) {
|
|
258
|
+
this._revealTab(active, ready && tabChanged);
|
|
253
259
|
}
|
|
254
260
|
// Exposed for ::part(indicator) styles that fill the tab rather than underline it.
|
|
255
|
-
setStyle(indicator, '--zn-navbar-indicator-top', `${tab.top - box.top}px`);
|
|
256
|
-
setStyle(indicator, '--zn-navbar-indicator-height', `${tab.height}px`);
|
|
261
|
+
setStyle(indicator, '--zn-navbar-indicator-top', `${(tab.top - box.top) / scaleY}px`);
|
|
262
|
+
setStyle(indicator, '--zn-navbar-indicator-height', `${tab.height / scaleY}px`);
|
|
257
263
|
indicator.classList.toggle('navbar__indicator--shown', true);
|
|
258
264
|
if (previous && Math.abs(previous.left - target.left) < 0.5 && Math.abs(previous.right - target.right) < 0.5) {
|
|
259
265
|
return;
|
|
@@ -271,7 +277,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
271
277
|
indicator.style.width = `${target.right - target.left}px`;
|
|
272
278
|
this._indicatorTarget = target;
|
|
273
279
|
if (slide) {
|
|
274
|
-
slideTabIndicator(indicator, {left: drawn.left
|
|
280
|
+
slideTabIndicator(indicator, {left: toStrip(drawn.left), right: toStrip(drawn.right)}, target);
|
|
275
281
|
}
|
|
276
282
|
|
|
277
283
|
// The first placement jumps into position; only later moves animate.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {ifDefined} from "lit/directives/if-defined.js";
|
|
2
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
3
2
|
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
4
3
|
import {HasSlotController} from "../../internal/slot";
|
|
4
|
+
import {ifDefined} from "lit/directives/if-defined.js";
|
|
5
5
|
import {property, state} from 'lit/decorators.js';
|
|
6
6
|
import {registerCosmicBorder} from "../../internal/cosmic-border";
|
|
7
7
|
import ZincElement from '../../internal/zinc-element';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
2
|
import {aTimeout, expect, fixture, html} from '@open-wc/testing';
|
|
3
|
-
import {centre,
|
|
3
|
+
import {centre, dragTo, drop, startDrag} from '../../internal/test-drag';
|
|
4
4
|
|
|
5
5
|
describe('<zn-priority-list>', () => {
|
|
6
6
|
it('should render a component', async () => {
|
|
@@ -989,6 +989,30 @@ describe('<zn-select> requires', () => {
|
|
|
989
989
|
await c.updateComplete;
|
|
990
990
|
expect(c.disabled, 'both filled').to.be.false;
|
|
991
991
|
});
|
|
992
|
+
|
|
993
|
+
it('re-enables a conditional select when the form resets', async () => {
|
|
994
|
+
const form = await fixture<HTMLFormElement>(html`
|
|
995
|
+
<form>
|
|
996
|
+
<zn-select id="allowed" name="allowed" multiple value="" provider="conditional" conditional="blocked">
|
|
997
|
+
<zn-option value="a">A</zn-option>
|
|
998
|
+
</zn-select>
|
|
999
|
+
<zn-select id="blocked" name="blocked" multiple value="" provider="conditional" conditional="allowed">
|
|
1000
|
+
<zn-option value="a">A</zn-option>
|
|
1001
|
+
</zn-select>
|
|
1002
|
+
</form>
|
|
1003
|
+
`);
|
|
1004
|
+
const allowed = form.querySelector<ZnSelect>('#allowed')!;
|
|
1005
|
+
const blocked = form.querySelector<ZnSelect>('#blocked')!;
|
|
1006
|
+
|
|
1007
|
+
blocked.value = ['a'];
|
|
1008
|
+
blocked.dispatchEvent(new Event('zn-change'));
|
|
1009
|
+
expect(allowed.disabled).to.be.true;
|
|
1010
|
+
|
|
1011
|
+
form.reset();
|
|
1012
|
+
|
|
1013
|
+
await waitUntil(() => !allowed.disabled);
|
|
1014
|
+
expect(allowed.disabled).to.be.false;
|
|
1015
|
+
});
|
|
992
1016
|
});
|
|
993
1017
|
|
|
994
1018
|
describe('<zn-select> empty state', () => {
|
|
@@ -4,8 +4,8 @@ import {on} from "../../utilities/on";
|
|
|
4
4
|
import {Store} from "../../internal/storage";
|
|
5
5
|
import ZincElement from '../../internal/zinc-element';
|
|
6
6
|
|
|
7
|
-
import styles from './split-pane.scss';
|
|
8
7
|
import { PropertyValues } from "@lit/reactive-element";
|
|
8
|
+
import styles from './split-pane.scss';
|
|
9
9
|
|
|
10
10
|
type NavigationItem = {
|
|
11
11
|
caption: string;
|
|
@@ -150,6 +150,7 @@ export default class ZnTable extends ZincElement {
|
|
|
150
150
|
tableBody() {
|
|
151
151
|
const rows: any = [];
|
|
152
152
|
this.hasActions = false;
|
|
153
|
+
const anyRowHasActions = this.rows.some((row: any) => Array.isArray(row?.actions) && row.actions.length > 0);
|
|
153
154
|
this.rows.forEach((row: any, _: any) => {
|
|
154
155
|
const rowHtml = [];
|
|
155
156
|
const basicData = !row.hasOwnProperty('caption') && !row.hasOwnProperty('data');
|
|
@@ -185,8 +186,10 @@ export default class ZnTable extends ZincElement {
|
|
|
185
186
|
iconHtml = html`
|
|
186
187
|
<zn-icon size="${iconSize}" src="${icon}"></zn-icon>`;
|
|
187
188
|
}
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
// An invisible menu icon keeps captions aligned with rows that do have a menu.
|
|
190
|
+
let actionsHtml = anyRowHasActions
|
|
191
|
+
? html`<div class="actions actions--placeholder" aria-hidden="true"><zn-icon src="more_vert"></zn-icon></div>`
|
|
192
|
+
: html`<div class="actions"></div>`;
|
|
190
193
|
if (actions && actions.length > 0) {
|
|
191
194
|
actionsHtml = html`
|
|
192
195
|
<div class="actions">
|
|
@@ -24,4 +24,17 @@ describe('<zn-table>', () => {
|
|
|
24
24
|
link.click();
|
|
25
25
|
expect(clicks).to.equal(2);
|
|
26
26
|
});
|
|
27
|
+
|
|
28
|
+
it('reserves the menu column on rows without actions when another row has them', async () => {
|
|
29
|
+
const data = {header: ['Name'], items: [
|
|
30
|
+
{caption: 'Me', data: []},
|
|
31
|
+
{caption: 'Them', actions: [{title: 'Edit', path: '/edit'}], data: []},
|
|
32
|
+
]};
|
|
33
|
+
const el = await fixture<HTMLElement>(html`<zn-table data="${JSON.stringify(data)}"></zn-table>`);
|
|
34
|
+
await (el as unknown as {updateComplete: Promise<unknown>}).updateComplete;
|
|
35
|
+
|
|
36
|
+
const cells = el.shadowRoot!.querySelectorAll<HTMLElement>('td.capcol .actions');
|
|
37
|
+
expect(cells[0].classList.contains('actions--placeholder')).to.be.true;
|
|
38
|
+
expect(cells[0].getBoundingClientRect().width).to.equal(cells[1].getBoundingClientRect().width);
|
|
39
|
+
});
|
|
27
40
|
});
|
|
@@ -14,11 +14,11 @@ import {HasSlotController} from "../../internal/slot";
|
|
|
14
14
|
import {ifDefined} from "lit/directives/if-defined.js";
|
|
15
15
|
import {md5} from "../../utilities/md5";
|
|
16
16
|
import {MutationController} from '@lit-labs/observers/mutation-controller.js';
|
|
17
|
+
import {onHoverIntent} from '../../internal/hover-intent';
|
|
18
|
+
import {pointerInitiated} from '../../internal/input-modality';
|
|
17
19
|
import {property} from 'lit/decorators.js';
|
|
18
20
|
import {Store} from "../../internal/storage";
|
|
19
21
|
import ZincElement from '../../internal/zinc-element';
|
|
20
|
-
import {onHoverIntent} from '../../internal/hover-intent';
|
|
21
|
-
import {pointerInitiated} from '../../internal/input-modality';
|
|
22
22
|
|
|
23
23
|
// Tabs load in such a way that the global sheet has to be re-applied inside the shadow root.
|
|
24
24
|
import bootStyles from '../../../scss/boot.scss';
|
|
@@ -24,7 +24,10 @@ export class ConditionalController implements ReactiveController {
|
|
|
24
24
|
private conditionals: ValuedElement[] = [];
|
|
25
25
|
private required: ValuedElement[] = [];
|
|
26
26
|
private initiallyDisabled = false;
|
|
27
|
+
private forms = new Set<HTMLFormElement>();
|
|
27
28
|
private readonly handleChange = () => this.checkConditionals();
|
|
29
|
+
// Controls restore their values in their own reset listeners, so check once they all have
|
|
30
|
+
private readonly handleReset = () => setTimeout(this.handleChange);
|
|
28
31
|
|
|
29
32
|
constructor(host: ReactiveControllerHost & Element & ConditionalHost) {
|
|
30
33
|
(this.host = host).addController(this);
|
|
@@ -45,7 +48,10 @@ export class ConditionalController implements ReactiveController {
|
|
|
45
48
|
watched.forEach(el => {
|
|
46
49
|
el.addEventListener('zn-change', this.handleChange);
|
|
47
50
|
el.addEventListener('zn-input', this.handleChange);
|
|
51
|
+
const form = el.closest('form');
|
|
52
|
+
if (form) this.forms.add(form);
|
|
48
53
|
});
|
|
54
|
+
this.forms.forEach(form => form.addEventListener('reset', this.handleReset));
|
|
49
55
|
|
|
50
56
|
// trigger the check once to initialize
|
|
51
57
|
this.checkConditionals();
|
|
@@ -86,8 +92,11 @@ export class ConditionalController implements ReactiveController {
|
|
|
86
92
|
el.removeEventListener('zn-input', this.handleChange);
|
|
87
93
|
});
|
|
88
94
|
|
|
95
|
+
this.forms.forEach(form => form.removeEventListener('reset', this.handleReset));
|
|
96
|
+
|
|
89
97
|
this.conditionals = [];
|
|
90
98
|
this.required = [];
|
|
99
|
+
this.forms.clear();
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
/** Re-evaluate the conditional state. Call from the host when needed. */
|