@kubex/zinc 1.1.28 → 1.1.31
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/custom-elements-manifest.config.js +2 -2
- package/dist/custom-elements.json +1910 -362
- package/dist/vscode.html-custom-data.json +55 -14
- package/dist/web-types.json +185 -32
- package/dist/zn.d.ts +684 -16
- package/dist/zn.min.js +1325 -929
- package/docs/pages/components/flow-builder-troubleshooter-demo.njk +106 -78
- package/docs/pages/components/flow-builder.md +422 -66
- package/docs/pages/components/page-builder.md +167 -0
- package/docs/pages/components/settings-container.md +37 -2
- package/package.json +1 -1
- package/src/components/datepicker/datepicker.scss +0 -10
- package/src/components/flow-builder/flow-builder.component.ts +377 -16
- package/src/components/flow-builder/flow-builder.scss +398 -250
- package/src/components/flow-builder/flow-builder.test.ts +241 -4
- package/src/components/flow-builder/flow-layout.ts +42 -17
- package/src/components/flow-builder/flow.types.ts +168 -43
- package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.component.ts +300 -0
- package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.scss +222 -0
- package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.test.ts +125 -0
- package/src/components/flow-builder/modules/flow-branch-conditions/index.ts +12 -0
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +184 -26
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +170 -120
- package/src/components/flow-builder/modules/flow-node/flow-node.scss +42 -42
- package/src/components/flow-builder/modules/flow-step/flow-step.component.ts +2 -1
- package/src/components/flow-builder/modules/flow-step/flow-step.scss +25 -17
- package/src/components/header/header.scss +3 -1
- package/src/components/icon-picker/icon-picker.component.ts +20 -37
- package/src/components/icon-picker/icon-picker.scss +5 -45
- package/src/components/page-builder/index.ts +14 -0
- package/src/components/page-builder/modules/page-palette-item/index.ts +12 -0
- package/src/components/page-builder/modules/page-palette-item/page-palette-item.component.ts +71 -0
- package/src/components/page-builder/modules/page-palette-item/page-palette-item.scss +70 -0
- package/src/components/page-builder/modules/page-palette-item/page-palette-item.test.ts +20 -0
- package/src/components/page-builder/modules/page-section-card/index.ts +12 -0
- package/src/components/page-builder/modules/page-section-card/page-section-card.component.ts +93 -0
- package/src/components/page-builder/modules/page-section-card/page-section-card.scss +92 -0
- package/src/components/page-builder/modules/page-section-card/page-section-card.test.ts +50 -0
- package/src/components/page-builder/page-builder.component.ts +1053 -0
- package/src/components/page-builder/page-builder.scss +494 -0
- package/src/components/page-builder/page-builder.test.ts +464 -0
- package/src/components/page-builder/page-registry.ts +48 -0
- package/src/components/page-builder/page.types.ts +75 -0
- package/src/components/panel/panel.scss +1 -0
- package/src/components/settings-container/settings-container.component.ts +74 -9
- package/src/components/settings-container/settings-container.scss +75 -0
- package/src/components/settings-container/settings-container.test.ts +35 -0
- package/src/events/events.ts +2 -0
- package/src/events/zn-page-change.ts +9 -0
- package/src/events/zn-page-selection-change.ts +7 -0
- package/src/zinc.ts +4 -0
- package/web-test-runner.config.js +6 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ZnPagePaletteItem from './page-palette-item.component';
|
|
2
|
+
|
|
3
|
+
export * from './page-palette-item.component';
|
|
4
|
+
export default ZnPagePaletteItem;
|
|
5
|
+
|
|
6
|
+
ZnPagePaletteItem.define('zn-page-palette-item');
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
'zn-page-palette-item': ZnPagePaletteItem;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
2
|
+
import {ifDefined} from 'lit/directives/if-defined.js';
|
|
3
|
+
import {property} from 'lit/decorators.js';
|
|
4
|
+
import ZincElement from '../../../../internal/zinc-element';
|
|
5
|
+
import ZnIcon from '../../../icon';
|
|
6
|
+
|
|
7
|
+
import {PAGE_TYPE_MIME} from '../../page.types';
|
|
8
|
+
|
|
9
|
+
import styles from './page-palette-item.scss';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @summary A draggable palette entry in `<zn-page-builder>`, representing a registered
|
|
13
|
+
* section type. Drag it onto the canvas to add that section. Unlike zn-page-section-card
|
|
14
|
+
* (host-wired), this element wires its own drag behaviour so it is draggable standalone.
|
|
15
|
+
* @documentation https://zinc.style/components/page-palette-item
|
|
16
|
+
* @status experimental
|
|
17
|
+
* @since 1.0
|
|
18
|
+
*
|
|
19
|
+
* @dependency zn-icon
|
|
20
|
+
*
|
|
21
|
+
* @csspart base - The card row.
|
|
22
|
+
*/
|
|
23
|
+
export default class ZnPagePaletteItem extends ZincElement {
|
|
24
|
+
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
25
|
+
|
|
26
|
+
static dependencies = {'zn-icon': ZnIcon};
|
|
27
|
+
|
|
28
|
+
/** The section type id this item creates when dropped. */
|
|
29
|
+
@property() type: string;
|
|
30
|
+
@property() label: string;
|
|
31
|
+
@property() description: string;
|
|
32
|
+
@property() icon: string;
|
|
33
|
+
@property({attribute: 'icon-library'}) iconLibrary: string;
|
|
34
|
+
@property() color: string;
|
|
35
|
+
|
|
36
|
+
connectedCallback() {
|
|
37
|
+
super.connectedCallback();
|
|
38
|
+
this.draggable = true;
|
|
39
|
+
this.addEventListener('dragstart', this._onDragStart);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
disconnectedCallback() {
|
|
43
|
+
this.removeEventListener('dragstart', this._onDragStart);
|
|
44
|
+
super.disconnectedCallback();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected updated(changed: PropertyValues) {
|
|
48
|
+
super.updated(changed);
|
|
49
|
+
this.style.setProperty('--section-accent', this.color ?? 'rgb(var(--zn-color-primary))');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private _onDragStart = (e: DragEvent) => {
|
|
53
|
+
if (!e.dataTransfer || !this.type) return;
|
|
54
|
+
e.dataTransfer.setData(PAGE_TYPE_MIME, this.type);
|
|
55
|
+
e.dataTransfer.effectAllowed = 'copy';
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
render() {
|
|
59
|
+
return html`
|
|
60
|
+
<div part="base" class="item">
|
|
61
|
+
<span class="item__icon">
|
|
62
|
+
<zn-icon src="${this.icon ?? 'widgets'}" library="${ifDefined(this.iconLibrary)}" size="16"></zn-icon>
|
|
63
|
+
</span>
|
|
64
|
+
<span class="item__text">
|
|
65
|
+
<span class="item__label">${this.label ?? ''}</span>
|
|
66
|
+
${this.description ? html`<span class="item__description">${this.description}</span>` : ''}
|
|
67
|
+
</span>
|
|
68
|
+
</div>
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
@use "../../../../wc";
|
|
2
|
+
|
|
3
|
+
// The card chrome lives on an inner wrapper, not :host — document-level CSS
|
|
4
|
+
// resets (e.g. the docs site's `*` border reset) override :host rules but
|
|
5
|
+
// cannot reach inside the shadow root.
|
|
6
|
+
:host {
|
|
7
|
+
--section-accent: rgb(var(--zn-color-primary));
|
|
8
|
+
|
|
9
|
+
display: block;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:host([hidden]) {
|
|
13
|
+
display: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.item {
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: 10px;
|
|
20
|
+
padding: 8px 10px;
|
|
21
|
+
background: rgb(var(--zn-panel));
|
|
22
|
+
border: 1px solid rgb(var(--zn-border-color));
|
|
23
|
+
border-radius: 8px;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
cursor: grab;
|
|
26
|
+
transition: border-color 0.12s ease, box-shadow 0.12s ease;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.item:hover {
|
|
30
|
+
border-color: rgb(var(--zn-color-border-active));
|
|
31
|
+
box-shadow: 0 1px 3px rgba(var(--zn-shadow), 0.4);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:host(:active) .item {
|
|
35
|
+
cursor: grabbing;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.item__icon {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
flex: 0 0 auto;
|
|
43
|
+
width: 28px;
|
|
44
|
+
height: 28px;
|
|
45
|
+
border-radius: 6px;
|
|
46
|
+
background: color-mix(in srgb, var(--section-accent) 15%, transparent);
|
|
47
|
+
color: var(--section-accent);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.item__text {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
flex: 1 1 auto;
|
|
54
|
+
min-width: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.item__label {
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
text-overflow: ellipsis;
|
|
61
|
+
font-size: 0.8125rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.item__description {
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
overflow: hidden;
|
|
67
|
+
text-overflow: ellipsis;
|
|
68
|
+
font-size: 0.75rem;
|
|
69
|
+
color: rgb(var(--zn-color-muted-text));
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import '../../../../../dist/zn.min.js';
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnPagePaletteItem from './page-palette-item.component';
|
|
4
|
+
|
|
5
|
+
describe('<zn-page-palette-item>', () => {
|
|
6
|
+
it('should render the label and description', async () => {
|
|
7
|
+
const el = await fixture<ZnPagePaletteItem>(html`
|
|
8
|
+
<zn-page-palette-item type="hero" label="Hero" description="Big banner"></zn-page-palette-item>`);
|
|
9
|
+
expect(el.shadowRoot?.querySelector('.item__label')?.textContent).to.equal('Hero');
|
|
10
|
+
expect(el.shadowRoot?.querySelector('.item__description')?.textContent).to.equal('Big banner');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should carry its type in the drag payload', async () => {
|
|
14
|
+
const el = await fixture<ZnPagePaletteItem>(html`
|
|
15
|
+
<zn-page-palette-item type="hero" label="Hero"></zn-page-palette-item>`);
|
|
16
|
+
const dataTransfer = new DataTransfer();
|
|
17
|
+
el.dispatchEvent(new DragEvent('dragstart', {dataTransfer, bubbles: true, cancelable: true}));
|
|
18
|
+
expect(dataTransfer.getData('application/x-zn-page-type')).to.equal('hero');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ZnPageSectionCard from './page-section-card.component';
|
|
2
|
+
|
|
3
|
+
export * from './page-section-card.component';
|
|
4
|
+
export default ZnPageSectionCard;
|
|
5
|
+
|
|
6
|
+
ZnPageSectionCard.define('zn-page-section-card');
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
'zn-page-section-card': ZnPageSectionCard;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
2
|
+
import {ifDefined} from 'lit/directives/if-defined.js';
|
|
3
|
+
import {property} from 'lit/decorators.js';
|
|
4
|
+
import ZincElement from '../../../../internal/zinc-element';
|
|
5
|
+
import ZnButton from '../../../button';
|
|
6
|
+
import ZnIcon from '../../../icon';
|
|
7
|
+
|
|
8
|
+
import styles from './page-section-card.scss';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @summary A section card on the `<zn-page-builder>` canvas: icon tile, label, one-line
|
|
12
|
+
* summary, and hover actions (duplicate / remove). Purely presentational — the builder
|
|
13
|
+
* wires up dragging, focus, selection and keyboard handling on the host element.
|
|
14
|
+
* @documentation https://zinc.style/components/page-section-card
|
|
15
|
+
* @status experimental
|
|
16
|
+
* @since 1.0
|
|
17
|
+
*
|
|
18
|
+
* @dependency zn-button
|
|
19
|
+
* @dependency zn-icon
|
|
20
|
+
*
|
|
21
|
+
* @event page-card-duplicate - The duplicate action was clicked (internal; not in the typed event map).
|
|
22
|
+
* @event page-card-remove - The remove action was clicked (internal; not in the typed event map).
|
|
23
|
+
*
|
|
24
|
+
* @csspart base - The card row.
|
|
25
|
+
*/
|
|
26
|
+
export default class ZnPageSectionCard extends ZincElement {
|
|
27
|
+
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
28
|
+
|
|
29
|
+
static dependencies = {
|
|
30
|
+
'zn-button': ZnButton,
|
|
31
|
+
'zn-icon': ZnIcon,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
@property() label = '';
|
|
35
|
+
@property() summary = '';
|
|
36
|
+
@property() icon = '';
|
|
37
|
+
@property({attribute: 'icon-library'}) iconLibrary: string;
|
|
38
|
+
@property() color = '';
|
|
39
|
+
@property({type: Boolean, reflect: true}) selected = false;
|
|
40
|
+
/** Set when the section's type has no registered template — renders greyed. */
|
|
41
|
+
@property({type: Boolean, reflect: true}) unknown = false;
|
|
42
|
+
|
|
43
|
+
protected updated(changed: PropertyValues) {
|
|
44
|
+
super.updated(changed);
|
|
45
|
+
this.style.setProperty('--section-accent', this.color || 'rgb(var(--zn-color-primary))');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private _action(e: Event, name: 'page-card-duplicate' | 'page-card-remove') {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
this.dispatchEvent(new CustomEvent(name, {bubbles: true, composed: true}));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Keep Enter/Space on the action buttons from reaching the host, where the
|
|
54
|
+
// builder's card keydown handler would preventDefault and suppress the
|
|
55
|
+
// button's native activation.
|
|
56
|
+
private _actionKeydown(e: KeyboardEvent) {
|
|
57
|
+
if (e.key === 'Enter' || e.key === ' ') e.stopPropagation();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
render() {
|
|
61
|
+
return html`
|
|
62
|
+
<div part="base" class="card">
|
|
63
|
+
<span class="card__icon">
|
|
64
|
+
<zn-icon src="${this.icon || 'widgets'}" library="${ifDefined(this.iconLibrary)}" size="18"></zn-icon>
|
|
65
|
+
</span>
|
|
66
|
+
<span class="card__text">
|
|
67
|
+
<span class="card__label">${this.label}</span>
|
|
68
|
+
${this.summary ? html`<span class="card__summary">${this.summary}</span>` : ''}
|
|
69
|
+
</span>
|
|
70
|
+
<span class="card__actions" @keydown="${this._actionKeydown}">
|
|
71
|
+
<zn-button
|
|
72
|
+
class="card__action"
|
|
73
|
+
icon-button="small"
|
|
74
|
+
plain
|
|
75
|
+
icon="content_copy"
|
|
76
|
+
icon-size="14"
|
|
77
|
+
title="Duplicate section"
|
|
78
|
+
aria-label="Duplicate section"
|
|
79
|
+
@click="${(e: Event) => this._action(e, 'page-card-duplicate')}"></zn-button>
|
|
80
|
+
<zn-button
|
|
81
|
+
class="card__action"
|
|
82
|
+
icon-button="small"
|
|
83
|
+
plain
|
|
84
|
+
icon="delete"
|
|
85
|
+
icon-size="14"
|
|
86
|
+
title="Remove section"
|
|
87
|
+
aria-label="Remove section"
|
|
88
|
+
@click="${(e: Event) => this._action(e, 'page-card-remove')}"></zn-button>
|
|
89
|
+
</span>
|
|
90
|
+
</div>
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
@use "../../../../wc";
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
--section-accent: rgb(var(--zn-color-primary));
|
|
5
|
+
|
|
6
|
+
display: block;
|
|
7
|
+
width: 100%;
|
|
8
|
+
max-width: var(--pb-card-width, 560px);
|
|
9
|
+
margin: 0 auto;
|
|
10
|
+
cursor: grab;
|
|
11
|
+
outline: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:host(:active) {
|
|
15
|
+
cursor: grabbing;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.card {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 12px;
|
|
22
|
+
padding: 12px 14px;
|
|
23
|
+
background: rgb(var(--zn-panel));
|
|
24
|
+
border: 1px solid rgb(var(--zn-border-color));
|
|
25
|
+
border-radius: 8px;
|
|
26
|
+
transition: border-color 0.12s ease, box-shadow 0.12s ease;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:host(:hover) .card,
|
|
30
|
+
:host(:focus-visible) .card {
|
|
31
|
+
border-color: rgb(var(--zn-color-border-active));
|
|
32
|
+
box-shadow: 0 1px 3px rgba(var(--zn-shadow), 0.4);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:host([selected]) .card {
|
|
36
|
+
border-color: var(--section-accent);
|
|
37
|
+
box-shadow: 0 0 0 1px var(--section-accent);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:host([unknown]) .card {
|
|
41
|
+
opacity: 0.6;
|
|
42
|
+
border-style: dashed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.card__icon {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
flex: 0 0 auto;
|
|
50
|
+
width: 34px;
|
|
51
|
+
height: 34px;
|
|
52
|
+
border-radius: 8px;
|
|
53
|
+
background: color-mix(in srgb, var(--section-accent) 15%, transparent);
|
|
54
|
+
color: var(--section-accent);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.card__text {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
flex: 1 1 auto;
|
|
61
|
+
min-width: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.card__label {
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
font-size: 13px;
|
|
67
|
+
white-space: nowrap;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
text-overflow: ellipsis;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.card__summary {
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
opacity: 0.7;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
text-overflow: ellipsis;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Space is always reserved (visibility, not display) so the card never
|
|
81
|
+
// changes size or shifts its text when the actions appear on hover.
|
|
82
|
+
.card__actions {
|
|
83
|
+
display: flex;
|
|
84
|
+
gap: 4px;
|
|
85
|
+
visibility: hidden;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:host(:hover) .card__actions,
|
|
89
|
+
:host(:focus-within) .card__actions,
|
|
90
|
+
:host([selected]) .card__actions {
|
|
91
|
+
visibility: visible;
|
|
92
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import '../../../../../dist/zn.min.js';
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnPageSectionCard from './page-section-card.component';
|
|
4
|
+
|
|
5
|
+
describe('<zn-page-section-card>', () => {
|
|
6
|
+
it('should render the label and summary', async () => {
|
|
7
|
+
const el = await fixture<ZnPageSectionCard>(html`
|
|
8
|
+
<zn-page-section-card label="Hero" summary="Big banner"></zn-page-section-card>`);
|
|
9
|
+
expect(el.shadowRoot?.querySelector('.card__label')?.textContent).to.equal('Hero');
|
|
10
|
+
expect(el.shadowRoot?.querySelector('.card__summary')?.textContent).to.equal('Big banner');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should dispatch action events without triggering selection clicks', async () => {
|
|
14
|
+
const el = await fixture<ZnPageSectionCard>(html`
|
|
15
|
+
<zn-page-section-card label="Hero"></zn-page-section-card>`);
|
|
16
|
+
const fired: string[] = [];
|
|
17
|
+
el.addEventListener('page-card-duplicate', () => fired.push('duplicate'));
|
|
18
|
+
el.addEventListener('page-card-remove', () => fired.push('remove'));
|
|
19
|
+
el.addEventListener('click', () => fired.push('click'));
|
|
20
|
+
|
|
21
|
+
// Real MouseEvents, not .click() — zn-button overrides the native click()
|
|
22
|
+
// method with internal handling that dispatches no event.
|
|
23
|
+
const buttons = el.shadowRoot!.querySelectorAll('zn-button.card__action');
|
|
24
|
+
const click = () => new MouseEvent('click', {bubbles: true, composed: true, cancelable: true});
|
|
25
|
+
buttons[0].dispatchEvent(click());
|
|
26
|
+
buttons[1].dispatchEvent(click());
|
|
27
|
+
|
|
28
|
+
expect(fired).to.deep.equal(['duplicate', 'remove']); // stopPropagation keeps click out
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should keep Enter/Space on action buttons from reaching the host', async () => {
|
|
32
|
+
const el = await fixture<ZnPageSectionCard>(html`
|
|
33
|
+
<zn-page-section-card label="Hero"></zn-page-section-card>`);
|
|
34
|
+
let hostSawKeydown = false;
|
|
35
|
+
el.addEventListener('keydown', () => (hostSawKeydown = true));
|
|
36
|
+
|
|
37
|
+
const button = el.shadowRoot!.querySelector<HTMLButtonElement>('.card__action')!;
|
|
38
|
+
button.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter', bubbles: true, composed: true, cancelable: true}));
|
|
39
|
+
button.dispatchEvent(new KeyboardEvent('keydown', {key: ' ', bubbles: true, composed: true, cancelable: true}));
|
|
40
|
+
|
|
41
|
+
expect(hostSawKeydown, 'host keydown suppressed for button activation keys').to.be.false;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should reflect selected and unknown states', async () => {
|
|
45
|
+
const el = await fixture<ZnPageSectionCard>(html`
|
|
46
|
+
<zn-page-section-card label="Hero" selected unknown></zn-page-section-card>`);
|
|
47
|
+
expect(el.hasAttribute('selected')).to.be.true;
|
|
48
|
+
expect(el.hasAttribute('unknown')).to.be.true;
|
|
49
|
+
});
|
|
50
|
+
});
|