@kubex/zinc 1.1.102 → 1.1.103
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 +2 -2
- package/dist/web-types.json +1 -1
- package/dist/zn.d.ts +4 -2
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +394 -395
- package/docs/pages/components/remarkd-editor.md +1 -1
- package/package.json +1 -1
- package/scss/_root.scss +121 -8
- package/scss/shared/_base.scss +10 -4
- package/scss/shared/_button-mixin.scss +29 -0
- package/scss/shared/_button.scss +3 -33
- package/scss/themes/_aura.scss +87 -8
- package/scss/themes/_dark.scss +14 -2
- package/scss/themes/_light.scss +4 -3
- package/scss/themes/_modes.scss +32 -0
- package/src/components/animated-button/animated-button.component.ts +2 -1
- package/src/components/animated-button/animated-button.scss +1 -1
- package/src/components/bulk-actions/bulk-actions.component.ts +2 -1
- package/src/components/bulk-actions/bulk-actions.scss +0 -1
- package/src/components/button/button.component.ts +6 -1
- package/src/components/button/button.scss +1 -1
- package/src/components/chart/chart.component.ts +4 -0
- package/src/components/checkbox/checkbox.component.ts +3 -1
- package/src/components/checkbox/checkbox.scss +0 -2
- package/src/components/checkbox-group/checkbox-group.component.ts +2 -1
- package/src/components/checkbox-group/checkbox-group.scss +0 -1
- package/src/components/data-table/data-table.component.ts +3 -1
- package/src/components/data-table/data-table.scss +0 -1
- package/src/components/datepicker/datepicker.component.ts +2 -1
- package/src/components/datepicker/datepicker.scss +0 -1
- package/src/components/editor/modules/toolbar/toolbar.component.ts +3 -1
- package/src/components/editor/modules/toolbar/toolbar.scss +0 -1
- package/src/components/file/file.component.ts +2 -1
- package/src/components/file/file.scss +0 -1
- package/src/components/form-group/form-group.component.ts +2 -1
- package/src/components/form-group/form-group.scss +0 -1
- package/src/components/icon-picker/icon-picker.component.ts +8 -3
- package/src/components/icon-picker/icon-picker.scss +0 -1
- package/src/components/inline-edit/inline-edit.component.ts +2 -1
- package/src/components/inline-edit/inline-edit.scss +0 -1
- package/src/components/input/input.component.ts +2 -1
- package/src/components/input/input.scss +0 -1
- package/src/components/input-group/input-group.component.ts +2 -1
- package/src/components/input-group/input-group.scss +0 -1
- package/src/components/menu/menu.scss +6 -1
- package/src/components/page/page.scss +19 -5
- package/src/components/priority-list/priority-list.component.ts +2 -1
- package/src/components/priority-list/priority-list.scss +0 -1
- package/src/components/query-builder/query-builder.component.ts +2 -1
- package/src/components/query-builder/query-builder.scss +0 -1
- package/src/components/radio/radio.component.ts +3 -1
- package/src/components/radio/radio.scss +0 -2
- package/src/components/radio-group/radio-group.component.ts +2 -1
- package/src/components/radio-group/radio-group.scss +0 -1
- package/src/components/rating/rating.component.ts +2 -1
- package/src/components/rating/rating.scss +0 -1
- package/src/components/remarkd-editor/actions.ts +0 -4
- package/src/components/remarkd-editor/remarkd-editor.test.ts +5 -3
- package/src/components/schedule-builder/schedule-builder.component.ts +2 -1
- package/src/components/schedule-builder/schedule-builder.scss +0 -1
- package/src/components/select/select.component.ts +2 -1
- package/src/components/select/select.scss +0 -1
- package/src/components/tabs/tabs.component.ts +3 -1
- package/src/components/tabs/tabs.scss +0 -1
- package/src/components/textarea/textarea.component.ts +2 -1
- package/src/components/textarea/textarea.scss +0 -1
- package/src/components/tile/tile.component.ts +33 -20
- package/src/components/tile/tile.scss +2 -0
- package/src/components/tile/tile.test.ts +64 -3
- package/src/components/toggle/toggle.component.ts +2 -1
- package/src/components/toggle/toggle.scss +0 -1
- package/src/components/translations/translations.component.ts +2 -1
- package/src/components/translations/translations.scss +0 -1
- package/src/internal/theme.ts +37 -12
- package/src/internal/zinc-element.ts +7 -5
|
@@ -61,10 +61,21 @@ export default class ZnTile extends ZincElement {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
private _handleActionsClick(e: MouseEvent) {
|
|
64
|
-
if (this._isLink())
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
if (!this._isLink()) return;
|
|
65
|
+
|
|
66
|
+
// Let Rubix's delegated pagelet handler see an action's own link. For controls without
|
|
67
|
+
// navigation metadata, stop before the handler can walk up to the tile host's href.
|
|
68
|
+
for (const target of e.composedPath()) {
|
|
69
|
+
if (target === this) break;
|
|
70
|
+
if (!(target instanceof Element)) continue;
|
|
71
|
+
|
|
72
|
+
const href = target.getAttribute('href');
|
|
73
|
+
if (target.hasAttribute('data-uri') || (href !== null && href !== '' && !href.startsWith('#'))) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
67
76
|
}
|
|
77
|
+
|
|
78
|
+
e.stopPropagation();
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
render() {
|
|
@@ -77,11 +88,7 @@ export default class ZnTile extends ZincElement {
|
|
|
77
88
|
const hasImage = this.hasSlotController.test('image');
|
|
78
89
|
|
|
79
90
|
return html`
|
|
80
|
-
|
|
81
|
-
href="${ifDefined(this.href)}"
|
|
82
|
-
data-uri="${ifDefined(this.dataUri)}"
|
|
83
|
-
gaid="${ifDefined(this.gaid)}"
|
|
84
|
-
data-target="${ifDefined(this.dataTarget)}"
|
|
91
|
+
<div
|
|
85
92
|
class="${classMap({
|
|
86
93
|
tile: true,
|
|
87
94
|
'tile--flush': this.flush,
|
|
@@ -96,11 +103,15 @@ export default class ZnTile extends ZincElement {
|
|
|
96
103
|
'tile--has-actions': hasActions,
|
|
97
104
|
'tile--has-image': hasImage,
|
|
98
105
|
})}">
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
<${tag}
|
|
107
|
+
href="${ifDefined(this.href)}"
|
|
108
|
+
data-uri="${ifDefined(this.dataUri)}"
|
|
109
|
+
gaid="${ifDefined(this.gaid)}"
|
|
110
|
+
data-target="${ifDefined(this.dataTarget)}"
|
|
111
|
+
class="tile__link">
|
|
112
|
+
${!hasCaption && !hasDescription && !hasProperties && !hasActions ? html`
|
|
113
|
+
<slot></slot>
|
|
114
|
+
` : html`
|
|
104
115
|
<div class="tile__left">
|
|
105
116
|
${hasImage ? html`
|
|
106
117
|
<slot name="image" part="image" class="tile__image"></slot>` : html``}
|
|
@@ -113,15 +124,17 @@ export default class ZnTile extends ZincElement {
|
|
|
113
124
|
${this.description}</p>` : html`<slot name="description" class="tile__description"></slot>`}
|
|
114
125
|
</div>
|
|
115
126
|
</div>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<div class="tile__right">
|
|
119
127
|
${hasProperties ? html`
|
|
120
128
|
<slot name="properties" part="properties" class="tile__properties"></slot>` : ''}
|
|
121
|
-
|
|
129
|
+
`}
|
|
130
|
+
</${tag}>
|
|
131
|
+
|
|
132
|
+
${hasActions ? html`
|
|
133
|
+
<div class="tile__right">
|
|
134
|
+
<!-- Kept outside the link so slotted controls retain their default behaviour. -->
|
|
122
135
|
<slot name="actions" part="actions" class="tile__actions"
|
|
123
|
-
@click=${this._handleActionsClick}></slot
|
|
124
|
-
</div>`}
|
|
125
|
-
|
|
136
|
+
@click=${this._handleActionsClick}></slot>
|
|
137
|
+
</div>` : ''}
|
|
138
|
+
</div>`;
|
|
126
139
|
}
|
|
127
140
|
}
|
|
@@ -1,10 +1,71 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import {
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnTile from './tile.component';
|
|
3
4
|
|
|
4
|
-
describe('<zn-
|
|
5
|
+
describe('<zn-tile>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
6
|
-
const el = await fixture(html
|
|
7
|
+
const el = await fixture(html`<zn-tile></zn-tile>`);
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
it('should render its content as a link when href is set', async () => {
|
|
13
|
+
const el = await fixture<ZnTile>(html`
|
|
14
|
+
<zn-tile href="/users/leslie" caption="Leslie Alexander"></zn-tile>`);
|
|
15
|
+
|
|
16
|
+
const link = el.shadowRoot!.querySelector<HTMLAnchorElement>('a.tile__link')!;
|
|
17
|
+
expect(link).to.exist;
|
|
18
|
+
expect(link.getAttribute('href')).to.equal('/users/leslie');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should render actions outside the link', async () => {
|
|
22
|
+
const el = await fixture<ZnTile>(html`
|
|
23
|
+
<zn-tile href="/users/leslie" caption="Leslie Alexander">
|
|
24
|
+
<zn-button slot="actions">Edit</zn-button>
|
|
25
|
+
</zn-tile>`);
|
|
26
|
+
|
|
27
|
+
const link = el.shadowRoot!.querySelector<HTMLAnchorElement>('a.tile__link')!;
|
|
28
|
+
const actions = el.shadowRoot!.querySelector<HTMLSlotElement>('slot[name="actions"]')!;
|
|
29
|
+
expect(link.contains(actions)).to.be.false;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should not cancel clicks from a slotted action', async () => {
|
|
33
|
+
const el = await fixture<ZnTile>(html`
|
|
34
|
+
<zn-tile href="/users/leslie" caption="Leslie Alexander">
|
|
35
|
+
<zn-button slot="actions">Edit</zn-button>
|
|
36
|
+
</zn-tile>`);
|
|
37
|
+
|
|
38
|
+
const action = el.querySelector<HTMLElement>('zn-button')!;
|
|
39
|
+
const button = action.shadowRoot!.querySelector<HTMLButtonElement>('button')!;
|
|
40
|
+
let click: MouseEvent | undefined;
|
|
41
|
+
action.addEventListener('click', event => (click = event as MouseEvent));
|
|
42
|
+
|
|
43
|
+
button.click();
|
|
44
|
+
|
|
45
|
+
expect(click).to.exist;
|
|
46
|
+
expect(click!.defaultPrevented).to.be.false;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should let a linked action reach delegated navigation handlers', async () => {
|
|
50
|
+
const el = await fixture<ZnTile>(html`
|
|
51
|
+
<zn-tile href="/users/leslie" caption="Leslie Alexander">
|
|
52
|
+
<zn-button slot="actions" href="/users/leslie/edit" data-target="modal">Edit</zn-button>
|
|
53
|
+
</zn-tile>`);
|
|
54
|
+
|
|
55
|
+
const action = el.querySelector<HTMLElement>('zn-button')!;
|
|
56
|
+
const buttonLink = action.shadowRoot!.querySelector<HTMLAnchorElement>('a')!;
|
|
57
|
+
let selectedLink: Element | undefined;
|
|
58
|
+
const handleDocumentClick = (event: MouseEvent) => {
|
|
59
|
+
selectedLink = event.composedPath().find(target =>
|
|
60
|
+
target instanceof Element && target.matches('[href]')) as Element | undefined;
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener('click', handleDocumentClick, {once: true});
|
|
64
|
+
|
|
65
|
+
buttonLink.click();
|
|
66
|
+
|
|
67
|
+
expect(selectedLink).to.equal(buttonLink);
|
|
68
|
+
expect(selectedLink!.getAttribute('href')).to.equal('/users/leslie/edit');
|
|
69
|
+
expect(selectedLink!.getAttribute('data-target')).to.equal('modal');
|
|
70
|
+
});
|
|
10
71
|
});
|
|
@@ -8,6 +8,7 @@ import { live } from "lit/directives/live.js";
|
|
|
8
8
|
import { property, query, state } from 'lit/decorators.js';
|
|
9
9
|
import ZincElement, { type ZincFormControl } from '../../internal/zinc-element';
|
|
10
10
|
|
|
11
|
+
import formControlStyles from '../../form-control.scss';
|
|
11
12
|
import styles from './toggle.scss';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -32,7 +33,7 @@ import styles from './toggle.scss';
|
|
|
32
33
|
* @cssproperty --zn-toggle-margin - The margin around the toggle switch. Defaults to `8px 0`.
|
|
33
34
|
*/
|
|
34
35
|
export default class ZnToggle extends ZincElement implements ZincFormControl {
|
|
35
|
-
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
36
|
+
static styles: CSSResultGroup = [unsafeCSS(formControlStyles), unsafeCSS(styles)];
|
|
36
37
|
|
|
37
38
|
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'description');
|
|
38
39
|
|
|
@@ -19,10 +19,11 @@ import type {PropertyValues} from 'lit';
|
|
|
19
19
|
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
20
20
|
import type {ZnMenuSelectEvent} from '../../events/zn-menu-select';
|
|
21
21
|
|
|
22
|
+
import formControlStyles from '../../form-control.scss';
|
|
22
23
|
import styles from './translations.scss';
|
|
23
24
|
|
|
24
25
|
export default class ZnTranslations extends ZincElement implements ZincFormControl {
|
|
25
|
-
static styles = unsafeCSS(styles);
|
|
26
|
+
static styles = [unsafeCSS(formControlStyles), unsafeCSS(styles)];
|
|
26
27
|
static dependencies = {
|
|
27
28
|
'zn-button': ZnButton,
|
|
28
29
|
'zn-button-group': ZnButtonGroup,
|
package/src/internal/theme.ts
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import {signal, SignalWatcher} from '@lit-labs/signals';
|
|
2
2
|
|
|
3
|
+
// Theming has two independent dimensions:
|
|
4
|
+
// `t` — the theme family (base, aura, ...), carrying the identity/palette.
|
|
5
|
+
// `m` — the rendered mode ('light' | 'dark') the family is currently drawn in.
|
|
6
|
+
// The host shell owns both attributes on <html>; components mirror them so CSS
|
|
7
|
+
// selectors like `[m="dark"]` and `:host-context([t="aura"])` keep working.
|
|
8
|
+
|
|
9
|
+
function readRootAttribute(name: string, fallback: string): string {
|
|
10
|
+
if (typeof document === 'undefined') return fallback;
|
|
11
|
+
return document.documentElement.getAttribute(name)
|
|
12
|
+
|| document.body?.getAttribute(name)
|
|
13
|
+
|| fallback;
|
|
14
|
+
}
|
|
15
|
+
|
|
3
16
|
function getDefaultTheme(): string {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
17
|
+
return readRootAttribute('t', 'light');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getDefaultMode(): string {
|
|
21
|
+
return readRootAttribute('m', 'light');
|
|
8
22
|
}
|
|
9
23
|
|
|
10
24
|
export const themeSignal = signal<string>(getDefaultTheme());
|
|
25
|
+
export const modeSignal = signal<string>(getDefaultMode());
|
|
11
26
|
|
|
12
27
|
let listenerInstalled = false;
|
|
13
28
|
|
|
@@ -17,18 +32,28 @@ export function installThemeListener(): void {
|
|
|
17
32
|
|
|
18
33
|
window.addEventListener('theme-change', (e: Event) => {
|
|
19
34
|
const detail: unknown = (e as CustomEvent<unknown>).detail;
|
|
20
|
-
let
|
|
35
|
+
let theme: string | undefined;
|
|
36
|
+
let mode: string | undefined;
|
|
37
|
+
|
|
21
38
|
if (typeof detail === 'string') {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
// Legacy payload: the theme name on its own.
|
|
40
|
+
theme = detail;
|
|
41
|
+
} else if (detail && typeof detail === 'object') {
|
|
42
|
+
const d = detail as {theme?: unknown; mode?: unknown};
|
|
43
|
+
if (typeof d.theme === 'string') theme = d.theme;
|
|
44
|
+
if (typeof d.mode === 'string') mode = d.mode;
|
|
27
45
|
}
|
|
28
|
-
|
|
46
|
+
|
|
47
|
+
// Anything the event did not carry is read back off the document, which the
|
|
48
|
+
// shell always writes before dispatching.
|
|
49
|
+
if (theme === undefined) theme = getDefaultTheme();
|
|
50
|
+
if (mode === undefined) mode = getDefaultMode();
|
|
51
|
+
|
|
52
|
+
if (theme !== themeSignal.get()) themeSignal.set(theme);
|
|
53
|
+
if (mode !== modeSignal.get()) modeSignal.set(mode);
|
|
29
54
|
});
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
installThemeListener();
|
|
33
58
|
|
|
34
|
-
export {SignalWatcher};
|
|
59
|
+
export {SignalWatcher};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {LitElement, type PropertyValues} from "lit";
|
|
2
2
|
import {property} from "lit/decorators.js";
|
|
3
|
-
import {SignalWatcher, themeSignal} from "./theme";
|
|
3
|
+
import {modeSignal, SignalWatcher, themeSignal} from "./theme";
|
|
4
4
|
import type {
|
|
5
5
|
EventTypeDoesNotRequireDetail,
|
|
6
6
|
EventTypeRequiresDetail,
|
|
@@ -19,13 +19,15 @@ const ZincElementBase: typeof LitElement & Constructor<SignalWatcherApi> = Signa
|
|
|
19
19
|
export default class ZincElement extends ZincElementBase {
|
|
20
20
|
@property() dir: string; // LTR or RTL direction
|
|
21
21
|
@property() lang: string; // Language
|
|
22
|
-
@property({reflect: true}) t: string; // Theme (
|
|
22
|
+
@property({reflect: true}) t: string; // Theme family (base, aura, ...)
|
|
23
|
+
@property({reflect: true}) m: string; // Rendered mode (light or dark)
|
|
23
24
|
|
|
24
25
|
protected override willUpdate(changed: PropertyValues): void {
|
|
25
|
-
// Reading
|
|
26
|
-
//
|
|
27
|
-
//
|
|
26
|
+
// Reading these signals here subscribes this component to theme changes via
|
|
27
|
+
// the SignalWatcher mixin. The reflected attributes keep CSS selectors like
|
|
28
|
+
// `[m="dark"]` and `:host-context([t="aura"])` working inside shadow roots.
|
|
28
29
|
this.t = themeSignal.get();
|
|
30
|
+
this.m = modeSignal.get();
|
|
29
31
|
super.willUpdate(changed);
|
|
30
32
|
}
|
|
31
33
|
|