@kubex/zinc 1.0.25 → 1.0.98
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/.claude/project.md +556 -0
- package/.github/workflows/js_build_and_deploy.yaml +9 -10
- package/dist/custom-elements.json +13431 -8728
- package/dist/vscode.html-custom-data.json +571 -37
- package/dist/web-types.json +1439 -181
- package/dist/zn.d.ts +1642 -661
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1406 -891
- package/docs/_utilities/code-previews.cjs +10 -1
- package/docs/assets/scripts/docs.js +42 -18
- package/docs/data/data-table.json +229 -66
- package/docs/data/empty.json +6 -0
- package/docs/data/products-table.json +41 -193
- package/docs/pages/components/action-bar.md +121 -6
- package/docs/pages/components/alert.md +118 -15
- package/docs/pages/components/animated-button.md +299 -0
- package/docs/pages/components/audio-select.md +534 -0
- package/docs/pages/components/bulk-actions.md +79 -5
- package/docs/pages/components/button-group.md +235 -27
- package/docs/pages/components/button.md +139 -1
- package/docs/pages/components/chart.md +365 -9
- package/docs/pages/components/checkbox.md +387 -58
- package/docs/pages/components/chip.md +253 -33
- package/docs/pages/components/collapsible.md +393 -46
- package/docs/pages/components/cols.md +152 -30
- package/docs/pages/components/confirm.md +182 -16
- package/docs/pages/components/copy-button.md +169 -6
- package/docs/pages/components/data-select.md +194 -15
- package/docs/pages/components/data-table-filter.md +96 -5
- package/docs/pages/components/data-table-search.md +451 -0
- package/docs/pages/components/data-table-sort.md +66 -5
- package/docs/pages/components/data-table.md +727 -66
- package/docs/pages/components/datepicker.md +402 -7
- package/docs/pages/components/defined-label.md +120 -5
- package/docs/pages/components/dialog.md +339 -59
- package/docs/pages/components/dropdown.md +366 -11
- package/docs/pages/components/editor.md +604 -7
- package/docs/pages/components/empty-state.md +315 -16
- package/docs/pages/components/expanding-action.md +212 -28
- package/docs/pages/components/file.md +421 -12
- package/docs/pages/components/filter-container.md +158 -5
- package/docs/pages/components/filter-wrapper.md +167 -6
- package/docs/pages/components/form-group.md +383 -6
- package/docs/pages/components/hover-container.md +237 -6
- package/docs/pages/components/icon-picker.md +121 -0
- package/docs/pages/components/icon.md +454 -48
- package/docs/pages/components/inline-edit.md +787 -19
- package/docs/pages/components/input-group.md +207 -13
- package/docs/pages/components/input.md +194 -0
- package/docs/pages/components/key-container.md +115 -0
- package/docs/pages/components/key.md +101 -0
- package/docs/pages/components/menu.md +512 -6
- package/docs/pages/components/note.md +239 -36
- package/docs/pages/components/opt-group.md +107 -0
- package/docs/pages/components/pagination.md +332 -6
- package/docs/pages/components/pane.md +222 -6
- package/docs/pages/components/panel.md +213 -26
- package/docs/pages/components/popup.md +1354 -6
- package/docs/pages/components/priority-list.md +233 -0
- package/docs/pages/components/progress-bar.md +387 -6
- package/docs/pages/components/radio-group.md +242 -5
- package/docs/pages/components/radio.md +474 -6
- package/docs/pages/components/rating.md +331 -7
- package/docs/pages/components/reveal.md +524 -6
- package/docs/pages/components/scroll-container.md +552 -6
- package/docs/pages/components/select.md +762 -160
- package/docs/pages/components/skeleton.md +473 -30
- package/docs/pages/components/slideout.md +261 -5
- package/docs/pages/components/sp.md +99 -41
- package/docs/pages/components/split-button.md +347 -9
- package/docs/pages/components/split-pane.md +445 -6
- package/docs/pages/components/stat.md +549 -9
- package/docs/pages/components/status-indicator.md +230 -1
- package/docs/pages/components/stepper.md +563 -6
- package/docs/pages/components/tabs.md +439 -13
- package/docs/pages/components/textarea.md +415 -17
- package/docs/pages/components/tile.md +385 -26
- package/docs/pages/components/toggle.md +424 -6
- package/docs/pages/components/tooltip.md +367 -0
- package/docs/pages/components/translation-group.md +210 -0
- package/docs/pages/components/translations.md +319 -19
- package/docs/pages/components/vertical-stepper.md +401 -8
- package/docs/pages/components/well.md +300 -3
- package/docs/pages/getting-started/form-controls.md +162 -0
- package/docs/pages/index.md +116 -15
- package/package.json +5 -6
- package/scss/_global-spacing.scss +4 -0
- package/scss/_root.scss +2 -2
- package/scss/boot.scss +19 -0
- package/scss/shared/layout.scss +5 -0
- package/scss/themes/_light.scss +3 -3
- package/src/components/alert/alert.scss +1 -0
- package/src/components/animated-button/README.md +306 -0
- package/src/components/animated-button/animated-button.component.ts +229 -0
- package/src/components/animated-button/animated-button.scss +228 -0
- package/src/components/animated-button/animated-button.test.ts +143 -0
- package/src/components/animated-button/index.ts +12 -0
- package/src/components/button/button.component.ts +5 -0
- package/src/components/button-group/button-group.component.ts +25 -13
- package/src/components/button-group/button-group.scss +6 -0
- package/src/components/checkbox/checkbox.component.ts +4 -0
- package/src/components/checkbox/checkbox.scss +7 -4
- package/src/components/checkbox-group/checkbox-group.scss +7 -0
- package/src/components/chip/chip.component.ts +7 -2
- package/src/components/chip/chip.scss +16 -2
- package/src/components/collapsible/collapsible.component.ts +27 -20
- package/src/components/cols/cols.component.ts +14 -2
- package/src/components/cols/cols.scss +6 -12
- package/src/components/confirm/confirm.component.ts +7 -0
- package/src/components/copy-button/copy-button.component.ts +12 -11
- package/src/components/data-select/data-select.component.ts +215 -44
- package/src/components/data-select/data-select.scss +66 -6
- package/src/components/data-select/providers/currency-data-provider.ts +20 -6
- package/src/components/data-select/providers/provider.ts +1 -0
- package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
- package/src/components/data-table/data-table.component.ts +81 -22
- package/src/components/data-table-search/data-table-search.component.ts +184 -0
- package/src/components/data-table-search/data-table-search.scss +17 -0
- package/src/components/data-table-search/data-table-search.test.ts +11 -0
- package/src/components/data-table-search/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +347 -13
- package/src/components/dialog/dialog.component.ts +1 -1
- package/src/components/empty-state/empty-state.scss +6 -1
- package/src/components/header/header.scss +3 -3
- package/src/components/icon/icon.component.ts +23 -1
- package/src/components/icon/icon.scss +23 -0
- package/src/components/icon-picker/brand-icons.ts +24 -0
- package/src/components/icon-picker/icon-picker.component.ts +407 -0
- package/src/components/icon-picker/icon-picker.scss +205 -0
- package/src/components/icon-picker/index.ts +12 -0
- package/src/components/icon-picker/line-icons.ts +612 -0
- package/src/components/icon-picker/material-icons.ts +14543 -0
- package/src/components/inline-edit/inline-edit.component.ts +190 -46
- package/src/components/inline-edit/inline-edit.scss +29 -0
- package/src/components/inline-edit/inline-edit.test.ts +314 -1
- package/src/components/input/input.component.ts +324 -5
- package/src/components/input/input.scss +87 -0
- package/src/components/input-group/input-group.component.ts +28 -7
- package/src/components/input-group/input-group.scss +48 -10
- package/src/components/item/item.component.ts +11 -2
- package/src/components/item/item.scss +7 -0
- package/src/components/key/index.ts +12 -0
- package/src/components/key/key.component.ts +47 -0
- package/src/components/key/key.scss +38 -0
- package/src/components/key-container/index.ts +12 -0
- package/src/components/key-container/key-container.component.ts +142 -0
- package/src/components/key-container/key-container.scss +33 -0
- package/src/components/menu-item/menu-item.component.ts +20 -0
- package/src/components/menu-item/menu-item.scss +69 -2
- package/src/components/navbar/navbar.component.ts +103 -11
- package/src/components/navbar/navbar.scss +6 -1
- package/src/components/opt-group/index.ts +12 -0
- package/src/components/opt-group/opt-group.component.ts +74 -0
- package/src/components/opt-group/opt-group.scss +37 -0
- package/src/components/opt-group/opt-group.test.ts +27 -0
- package/src/components/option/option.component.ts +1 -16
- package/src/components/option/option.scss +4 -0
- package/src/components/panel/panel.component.ts +10 -8
- package/src/components/panel/panel.scss +20 -0
- package/src/components/priority-list/index.ts +12 -0
- package/src/components/priority-list/priority-list.component.ts +611 -0
- package/src/components/priority-list/priority-list.scss +185 -0
- package/src/components/priority-list/priority-list.test.ts +139 -0
- package/src/components/progress-bar/progress-bar.component.ts +22 -16
- package/src/components/radio/radio.scss +10 -3
- package/src/components/select/select.component.ts +812 -72
- package/src/components/select/select.scss +108 -2
- package/src/components/select/select.test.ts +147 -2
- package/src/components/settings-container/settings-container.component.ts +44 -19
- package/src/components/settings-container/settings-container.scss +1 -1
- package/src/components/skeleton/skeleton.component.ts +6 -1
- package/src/components/slideout/slideout.scss +8 -3
- package/src/components/sp/sp.component.ts +3 -1
- package/src/components/sp/sp.scss +19 -0
- package/src/components/stepper/stepper.component.ts +16 -10
- package/src/components/textarea/textarea.scss +0 -4
- package/src/components/tile/tile.component.ts +12 -3
- package/src/components/tile/tile.scss +1 -1
- package/src/components/timer/timer.component.ts +15 -2
- package/src/components/toggle/toggle.component.ts +29 -26
- package/src/components/toggle/toggle.scss +13 -1
- package/src/components/translation-group/index.ts +12 -0
- package/src/components/translation-group/translation-group.component.ts +207 -0
- package/src/components/translation-group/translation-group.scss +8 -0
- package/src/components/translations/translations.component.ts +90 -44
- package/src/components/translations/translations.scss +4 -0
- package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
- package/src/events/events.ts +12 -7
- package/src/events/zn-language-change.ts +7 -0
- package/src/events/zn-purchase.ts +11 -0
- package/src/events/zn-redirect.ts +7 -0
- package/src/events/zn-reorder.ts +7 -0
- package/src/events/zn-search-change.ts +11 -0
- package/src/events/zn-submit.ts +1 -1
- package/src/form-control.scss +4 -0
- package/src/internal/form-navigation.ts +510 -0
- package/src/internal/form.ts +6 -0
- package/src/zinc.ts +91 -83
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
flex-direction: row;
|
|
13
13
|
padding: 0 var(--zn-spacing-medium);
|
|
14
14
|
gap: var(--zn-spacing-2x-small);
|
|
15
|
+
min-height: 35px;
|
|
15
16
|
|
|
16
17
|
@include wc.container-query(null, md) {
|
|
17
18
|
--zn-item-label-max-width: 220px;
|
|
@@ -95,6 +96,12 @@
|
|
|
95
96
|
line-height: var(--zn-line-height-loose);
|
|
96
97
|
width: 100%;
|
|
97
98
|
flex-shrink: 0;
|
|
99
|
+
|
|
100
|
+
&--required::after {
|
|
101
|
+
content: var(--zn-input-required-content);
|
|
102
|
+
margin-inline-start: var(--zn-input-required-content-offset);
|
|
103
|
+
color: var(--zn-input-required-content-color);
|
|
104
|
+
}
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
&__description {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
2
|
+
import {property} from 'lit/decorators.js';
|
|
3
|
+
import ZincElement from '../../internal/zinc-element';
|
|
4
|
+
|
|
5
|
+
import styles from './key.scss';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @summary A legend key item, typically used alongside charts to label and toggle visibility of data series by category.
|
|
9
|
+
* @documentation https://zinc.style/components/key
|
|
10
|
+
* @status experimental
|
|
11
|
+
* @since 1.0
|
|
12
|
+
*
|
|
13
|
+
* @slot - The description of the key.
|
|
14
|
+
*/
|
|
15
|
+
export default class ZnKey extends ZincElement {
|
|
16
|
+
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
17
|
+
|
|
18
|
+
@property() icon: string = '';
|
|
19
|
+
@property() attribute: string = '';
|
|
20
|
+
@property() value: string = '';
|
|
21
|
+
@property() color: 'primary' | 'success' | 'warning' | 'error' | 'info' | 'neutral' = 'primary';
|
|
22
|
+
@property({type: Boolean, reflect: true}) active: boolean = false;
|
|
23
|
+
@property({attribute: 'icon-size', type: Number}) iconSize: number = 24;
|
|
24
|
+
|
|
25
|
+
private _handleClick() {
|
|
26
|
+
this.active = !this.active;
|
|
27
|
+
this.emit('zn-change');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
const chipType = this.active ? this.color : 'transparent';
|
|
32
|
+
|
|
33
|
+
return html`
|
|
34
|
+
<div class="key" @click="${this._handleClick}">
|
|
35
|
+
<zn-chip
|
|
36
|
+
.icon="${this.icon}"
|
|
37
|
+
.iconSize="${this.iconSize}"
|
|
38
|
+
.type="${chipType}"
|
|
39
|
+
size="medium"
|
|
40
|
+
></zn-chip>
|
|
41
|
+
<div class="key__description">
|
|
42
|
+
<slot></slot>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@use "../../wc";
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.key {
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: row;
|
|
11
|
+
gap: var(--zn-spacing-medium);
|
|
12
|
+
align-items: center;
|
|
13
|
+
text-align: left;
|
|
14
|
+
|
|
15
|
+
&__description {
|
|
16
|
+
font-size: var(--zn-font-size-small);
|
|
17
|
+
color: rgb(var(--zn-text-body));
|
|
18
|
+
opacity: 0.7;
|
|
19
|
+
line-height: var(--zn-line-height-normal);
|
|
20
|
+
user-select: none;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:host([active]) .key__label {
|
|
25
|
+
color: rgb(var(--zn-text-heading));
|
|
26
|
+
font-weight: 600;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:host(:not([active])) {
|
|
30
|
+
.key__description {
|
|
31
|
+
opacity: 0.6;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
zn-chip {
|
|
35
|
+
--zn-chip-color: rgb(var(--zn-text-body));
|
|
36
|
+
opacity: 0.5;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ZnKeyContainer from './key-container.component';
|
|
2
|
+
|
|
3
|
+
export * from './key-container.component';
|
|
4
|
+
export default ZnKeyContainer;
|
|
5
|
+
|
|
6
|
+
ZnKeyContainer.define('zn-key-container');
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
'zn-key-container': ZnKeyContainer;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {classMap} from "lit/directives/class-map.js";
|
|
2
|
+
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
3
|
+
import {deepQuerySelectorAll} from "../../utilities/query";
|
|
4
|
+
import {property, query} from 'lit/decorators.js';
|
|
5
|
+
import ZincElement from '../../internal/zinc-element';
|
|
6
|
+
import type ZnKey from "../key/key.component";
|
|
7
|
+
|
|
8
|
+
import styles from './key-container.scss';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @summary A legend container that manages key items, typically used alongside charts to toggle visibility of data series by category.
|
|
12
|
+
* @documentation https://zinc.style/components/key-container
|
|
13
|
+
* @status experimental
|
|
14
|
+
* @since 1.0
|
|
15
|
+
*
|
|
16
|
+
* @slot - The content to be filtered.
|
|
17
|
+
* @slot keys - The key items (zn-key) that define the filters.
|
|
18
|
+
*
|
|
19
|
+
* @event zn-change - Emitted when the set of active keys changes.
|
|
20
|
+
*/
|
|
21
|
+
export default class ZnKeyContainer extends ZincElement {
|
|
22
|
+
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
23
|
+
|
|
24
|
+
@query('slot[name="keys"]') keysSlot: HTMLSlotElement;
|
|
25
|
+
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
|
|
26
|
+
|
|
27
|
+
@property() position: 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start' = 'bottom-start';
|
|
28
|
+
@property() target: string = ''; // ID of the target element containing items
|
|
29
|
+
@property({attribute: 'item-selector'}) itemSelector: string = '[data-type]';
|
|
30
|
+
@property({attribute: 'filter-attribute'}) filterAttribute: string = '';
|
|
31
|
+
@property({attribute: 'no-scroll', type: Boolean}) noScroll: boolean = false;
|
|
32
|
+
|
|
33
|
+
private _hiddenElements: Set<Element> = new Set();
|
|
34
|
+
private _targetElement: HTMLElement | null = null;
|
|
35
|
+
|
|
36
|
+
connectedCallback() {
|
|
37
|
+
super.connectedCallback();
|
|
38
|
+
this.updateFilters();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
firstUpdated() {
|
|
42
|
+
if (this.target) {
|
|
43
|
+
const rootNode = this.getRootNode() as Document | ShadowRoot;
|
|
44
|
+
this._targetElement = rootNode.getElementById ? rootNode.getElementById(this.target) : document.getElementById(this.target);
|
|
45
|
+
}
|
|
46
|
+
this.updateFilters();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private _handleKeyChange() {
|
|
50
|
+
this.updateFilters();
|
|
51
|
+
this.emit('zn-change');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private getKeys(): ZnKey[] {
|
|
55
|
+
const keys = [];
|
|
56
|
+
if (this.keysSlot) {
|
|
57
|
+
keys.push(...this.keysSlot.assignedElements({flatten: true}));
|
|
58
|
+
}
|
|
59
|
+
if (this.defaultSlot) {
|
|
60
|
+
keys.push(...this.defaultSlot.assignedElements({flatten: true}));
|
|
61
|
+
}
|
|
62
|
+
return keys.filter(el => el.tagName.toLowerCase() === 'zn-key') as ZnKey[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private updateFilters() {
|
|
66
|
+
const keys = this.getKeys();
|
|
67
|
+
if (!keys || keys.length === 0) return;
|
|
68
|
+
|
|
69
|
+
// Reset hidden elements
|
|
70
|
+
this._hiddenElements.forEach(el => el.removeAttribute('hidden'));
|
|
71
|
+
this._hiddenElements.clear();
|
|
72
|
+
|
|
73
|
+
if (this.target && !this._targetElement) {
|
|
74
|
+
const rootNode = this.getRootNode() as Document | ShadowRoot;
|
|
75
|
+
this._targetElement = rootNode.getElementById?.(this.target) ?? document.getElementById(this.target);
|
|
76
|
+
}
|
|
77
|
+
let root: Element | Document | DocumentFragment | null = this._targetElement ?? null;
|
|
78
|
+
|
|
79
|
+
if (!root) {
|
|
80
|
+
const slotElements = this.defaultSlot?.assignedElements({flatten: true}) ?? [];
|
|
81
|
+
root = slotElements.some(el => el.tagName !== 'ZN-KEY')
|
|
82
|
+
? this
|
|
83
|
+
: this.parentElement ?? (this.parentNode as DocumentFragment);
|
|
84
|
+
}
|
|
85
|
+
if (!root) return;
|
|
86
|
+
|
|
87
|
+
const selector = this.filterAttribute ? `[${this.filterAttribute}]` : this.itemSelector;
|
|
88
|
+
const items = deepQuerySelectorAll(selector, root as HTMLElement, "");
|
|
89
|
+
items.forEach(item => {
|
|
90
|
+
if (item === this) return;
|
|
91
|
+
|
|
92
|
+
const matchesInactive = keys.some(key => !key.active && this.itemMatchesKey(item, key));
|
|
93
|
+
if (matchesInactive) {
|
|
94
|
+
item.setAttribute('hidden', '');
|
|
95
|
+
this._hiddenElements.add(item);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private itemMatchesKey(item: Element, key: ZnKey): boolean {
|
|
101
|
+
// 1. If the container specifies filterAttribute, use key.attribute as the value to look for
|
|
102
|
+
if (this.filterAttribute) {
|
|
103
|
+
const itemValue = item.getAttribute(this.filterAttribute);
|
|
104
|
+
if (!itemValue) return false;
|
|
105
|
+
|
|
106
|
+
const targetValue = key.attribute;
|
|
107
|
+
if (!targetValue) return false;
|
|
108
|
+
|
|
109
|
+
return itemValue.split(/\s+/).includes(targetValue);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 2. If key specifies attribute and value
|
|
113
|
+
if (key.attribute && key.value) {
|
|
114
|
+
const itemValue = item.getAttribute(key.attribute);
|
|
115
|
+
if (!itemValue) return false;
|
|
116
|
+
|
|
117
|
+
return itemValue.split(/\s+/).includes(key.value);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 3. If the key only specifies attribute (and no value), check for existence
|
|
121
|
+
if (key.attribute) {
|
|
122
|
+
return item.hasAttribute(key.attribute);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
render() {
|
|
129
|
+
return html`
|
|
130
|
+
<div class="${classMap({
|
|
131
|
+
'key-container': true,
|
|
132
|
+
'key-container--scroll': !this.noScroll,
|
|
133
|
+
})}" @zn-change="${this._handleKeyChange}">
|
|
134
|
+
${this.target ? '' : html`
|
|
135
|
+
<div class="key-container__content">
|
|
136
|
+
<slot @slotchange="${this.updateFilters.bind(this)}" class="key-container__keys"></slot>
|
|
137
|
+
</div>
|
|
138
|
+
`}
|
|
139
|
+
</div>
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@use "../../wc";
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: contents;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.key-container--scroll {
|
|
8
|
+
height: 100%;
|
|
9
|
+
width: 100%;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
position: relative;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.key-container__content {
|
|
15
|
+
height: 100%;
|
|
16
|
+
width: 100%;
|
|
17
|
+
overflow: auto;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.key-container__keys {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
gap: var(--zn-spacing-medium);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
::slotted(zn-key) {
|
|
28
|
+
flex: 0 0 auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
::slotted([hidden]) {
|
|
32
|
+
display: none !important;
|
|
33
|
+
}
|
|
@@ -78,6 +78,21 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
78
78
|
|
|
79
79
|
@property({type: Boolean, reflect: true}) confirm = false;
|
|
80
80
|
|
|
81
|
+
/** Removes all padding from the menu item. */
|
|
82
|
+
@property({type: Boolean, reflect: true}) flush = false;
|
|
83
|
+
|
|
84
|
+
/** Removes horizontal (left/right) padding only. Ignored if flush is set. */
|
|
85
|
+
@property({type: Boolean, reflect: true, attribute: 'flush-x'}) flushX = false;
|
|
86
|
+
|
|
87
|
+
/** Removes vertical (top/bottom) padding only. Ignored if flush is set. */
|
|
88
|
+
@property({type: Boolean, reflect: true, attribute: 'flush-y'}) flushY = false;
|
|
89
|
+
|
|
90
|
+
/** Removes the border from the menu item. */
|
|
91
|
+
@property({type: Boolean, reflect: true, attribute: 'no-border'}) noBorder = false;
|
|
92
|
+
|
|
93
|
+
/** Marks the menu item as currently active/selected. */
|
|
94
|
+
@property({type: Boolean, reflect: true}) active = false;
|
|
95
|
+
|
|
81
96
|
private readonly localize = new LocalizeController(this);
|
|
82
97
|
private readonly hasSlotController = new HasSlotController(this, 'submenu');
|
|
83
98
|
private submenuController: SubmenuController = new SubmenuController(this, this.hasSlotController, this.localize);
|
|
@@ -209,6 +224,11 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
209
224
|
'menu-item--success': this.color === 'success',
|
|
210
225
|
'menu-item--warning': this.color === 'warning',
|
|
211
226
|
'menu-item--transparent': this.color === 'transparent',
|
|
227
|
+
'menu-item--flush': this.flush,
|
|
228
|
+
'menu-item--flush-x': this.flushX && !this.flush,
|
|
229
|
+
'menu-item--flush-y': this.flushY && !this.flush,
|
|
230
|
+
'menu-item--no-border': this.noBorder,
|
|
231
|
+
'menu-item--active': this.active,
|
|
212
232
|
|
|
213
233
|
})}
|
|
214
234
|
?aria-haspopup="${this.isSubmenu()}"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
white-space: nowrap;
|
|
24
24
|
cursor: pointer;
|
|
25
25
|
border-bottom-width: 1px;
|
|
26
|
-
|
|
26
|
+
width: 100%;
|
|
27
27
|
text-decoration: none;
|
|
28
28
|
color: var(--color);
|
|
29
29
|
}
|
|
@@ -44,6 +44,72 @@
|
|
|
44
44
|
cursor: wait;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// Flush variants - remove padding
|
|
48
|
+
.menu-item--flush {
|
|
49
|
+
padding: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.menu-item--flush-x {
|
|
53
|
+
padding-left: 0;
|
|
54
|
+
padding-right: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.menu-item--flush-y {
|
|
58
|
+
padding-top: 0;
|
|
59
|
+
padding-bottom: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// No border variant
|
|
63
|
+
.menu-item--no-border {
|
|
64
|
+
border-bottom-width: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Active state - vertical strip indicator
|
|
68
|
+
.menu-item--active::before {
|
|
69
|
+
content: '';
|
|
70
|
+
position: absolute;
|
|
71
|
+
left: 0;
|
|
72
|
+
top: 0;
|
|
73
|
+
bottom: 0;
|
|
74
|
+
width: 3px;
|
|
75
|
+
background-color: var(--hover-color);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.menu-item.menu-item--active .menu-item__label {
|
|
79
|
+
font-weight: 700;
|
|
80
|
+
color: var(--hover-color);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.menu-item--rtl.menu-item--active::before {
|
|
84
|
+
left: auto;
|
|
85
|
+
right: 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Active state with color variants
|
|
89
|
+
.menu-item--active.menu-item--primary::before {
|
|
90
|
+
background-color: rgb(var(--zn-primary));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.menu-item--active.menu-item--error::before {
|
|
94
|
+
background-color: rgb(var(--zn-color-error));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.menu-item--active.menu-item--info::before {
|
|
98
|
+
background-color: rgb(var(--zn-color-info));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.menu-item--active.menu-item--warning::before {
|
|
102
|
+
background-color: rgb(var(--zn-color-warning));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.menu-item--active.menu-item--success::before {
|
|
106
|
+
background-color: rgb(var(--zn-color-success));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.menu-item--active.menu-item--secondary::before {
|
|
110
|
+
background-color: rgb(var(--zn-accent));
|
|
111
|
+
}
|
|
112
|
+
|
|
47
113
|
.menu-item .menu-item__label {
|
|
48
114
|
display: flex;
|
|
49
115
|
flex: 1 1 auto;
|
|
@@ -99,7 +165,8 @@
|
|
|
99
165
|
}
|
|
100
166
|
|
|
101
167
|
:host(:hover:not([aria-disabled='true'], :focus-visible)) .menu-item,
|
|
102
|
-
.menu-item--submenu-expanded
|
|
168
|
+
.menu-item--submenu-expanded,
|
|
169
|
+
.menu-item--active {
|
|
103
170
|
background-color: var(--hover-bg);
|
|
104
171
|
color: var(--hover-color);
|
|
105
172
|
}
|
|
@@ -2,12 +2,18 @@ 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
4
|
import {property} from 'lit/decorators.js';
|
|
5
|
+
import {Store} from "../../internal/storage";
|
|
5
6
|
import ZincElement from '../../internal/zinc-element';
|
|
6
7
|
import ZnDropdown from "../dropdown";
|
|
7
8
|
import type {ZnMenuSelectEvent} from "../../events/zn-menu-select";
|
|
8
9
|
|
|
9
10
|
import styles from './navbar.scss';
|
|
10
11
|
|
|
12
|
+
interface StoredTab {
|
|
13
|
+
uri: string;
|
|
14
|
+
title: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
/**
|
|
12
18
|
* @summary Short summary of the component's intended use.
|
|
13
19
|
* @documentation https://zinc.style/components/navbar
|
|
@@ -44,6 +50,11 @@ export default class ZnNavbar extends ZincElement {
|
|
|
44
50
|
@property({attribute: 'manual-add-items', type: Boolean}) manualAddItems = false;
|
|
45
51
|
@property({type: Boolean}) isolated = false;
|
|
46
52
|
|
|
53
|
+
@property({attribute: 'master-id', reflect: true}) masterId: string;
|
|
54
|
+
@property({attribute: 'store-key', type: String}) storeKey: string = '';
|
|
55
|
+
@property({attribute: 'store-ttl', type: Number, reflect: true}) storeTtl = 0;
|
|
56
|
+
@property({attribute: 'local-storage', type: Boolean, reflect: true}) localStorage: boolean;
|
|
57
|
+
|
|
47
58
|
private _preItems: NodeListOf<Element>;
|
|
48
59
|
private _postItems: NodeListOf<Element>;
|
|
49
60
|
@property()
|
|
@@ -59,6 +70,8 @@ export default class ZnNavbar extends ZincElement {
|
|
|
59
70
|
private _expandableMargin: number = 0;
|
|
60
71
|
private _totalItemWidth: number = 0;
|
|
61
72
|
|
|
73
|
+
protected _store: Store;
|
|
74
|
+
|
|
62
75
|
appendItem(item: Element) {
|
|
63
76
|
this._appended = this._appended || [];
|
|
64
77
|
this._appended.push(item);
|
|
@@ -72,6 +85,16 @@ export default class ZnNavbar extends ZincElement {
|
|
|
72
85
|
|
|
73
86
|
this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
|
|
74
87
|
this.resizeObserver.observe(this as HTMLElement); // Observe the parent node
|
|
88
|
+
|
|
89
|
+
if (!this.masterId) {
|
|
90
|
+
this.masterId = this.storeKey || Math.floor(Math.random() * 1000000).toString();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (this.storeKey && this.storeTtl === 0) {
|
|
94
|
+
this.storeTtl = 300;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this._store = new Store(this.localStorage ? window.localStorage : window.sessionStorage, "znnav:", this.storeTtl);
|
|
75
98
|
}
|
|
76
99
|
|
|
77
100
|
|
|
@@ -92,7 +115,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
92
115
|
let parent = this.parentElement;
|
|
93
116
|
let availableWidth = this.offsetWidth || parent?.offsetWidth || 0;
|
|
94
117
|
|
|
95
|
-
// Needs to grab the first available width that is
|
|
118
|
+
// Needs to grab the first available width that is 0
|
|
96
119
|
// This is to avoid issues with the parent/navbar not being visible
|
|
97
120
|
while (availableWidth === 0 && parent?.parentElement) {
|
|
98
121
|
parent = parent.parentElement;
|
|
@@ -129,7 +152,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
129
152
|
this._navItems?.classList.toggle('has-hidden', hasHidden && hideRemaining)
|
|
130
153
|
}
|
|
131
154
|
|
|
132
|
-
public addItem(item: Element): void {
|
|
155
|
+
public addItem(item: Element, persist: boolean = true): void {
|
|
133
156
|
const tabUri = item.getAttribute('tab-uri');
|
|
134
157
|
if (typeof tabUri !== 'string' || this._openedTabs.includes(tabUri)) {
|
|
135
158
|
return;
|
|
@@ -137,8 +160,15 @@ export default class ZnNavbar extends ZincElement {
|
|
|
137
160
|
this._openedTabs.push(tabUri);
|
|
138
161
|
const ul = this.shadowRoot?.querySelector('ul');
|
|
139
162
|
const dropdown = this.shadowRoot?.querySelector('[id="dropdown-item"]');
|
|
140
|
-
|
|
141
|
-
|
|
163
|
+
|
|
164
|
+
if (persist && dropdown) {
|
|
165
|
+
dropdown.querySelector('zn-dropdown')?.hide();
|
|
166
|
+
this._saveTabToStorage({
|
|
167
|
+
uri: tabUri,
|
|
168
|
+
title: (item as HTMLElement).innerText
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
142
172
|
if (dropdown) {
|
|
143
173
|
ul?.insertBefore(item, dropdown);
|
|
144
174
|
} else {
|
|
@@ -159,8 +189,21 @@ export default class ZnNavbar extends ZincElement {
|
|
|
159
189
|
if (this._navItems) {
|
|
160
190
|
const computed = getComputedStyle(this._navItems);
|
|
161
191
|
this._navItemsGap = parseInt(computed.columnGap);
|
|
192
|
+
|
|
193
|
+
this._navItems.addEventListener('click', (e) => {
|
|
194
|
+
const target = (e.target as HTMLElement).closest('li[tab-uri]');
|
|
195
|
+
if (target && this.storeKey) {
|
|
196
|
+
const uri = target.getAttribute('tab-uri');
|
|
197
|
+
if (uri) {
|
|
198
|
+
this._store.set(this.storeKey + ':active', uri);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
162
202
|
}
|
|
163
203
|
|
|
204
|
+
// Load persisted tabs before calculating widths
|
|
205
|
+
this._loadStoredTabs();
|
|
206
|
+
|
|
164
207
|
setTimeout(() => {
|
|
165
208
|
const items = this._navItems?.querySelectorAll('li') || [];
|
|
166
209
|
for (const item of items) {
|
|
@@ -182,7 +225,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
182
225
|
const li = document.createElement('li');
|
|
183
226
|
li.setAttribute('tab-uri', (e.detail.element as HTMLElement).getAttribute('data-path')!);
|
|
184
227
|
li.innerText = e.detail.value;
|
|
185
|
-
this.addItem(li);
|
|
228
|
+
this.addItem(li, true);
|
|
186
229
|
setTimeout(() => {
|
|
187
230
|
li.click();
|
|
188
231
|
}, 300);
|
|
@@ -192,8 +235,55 @@ export default class ZnNavbar extends ZincElement {
|
|
|
192
235
|
}
|
|
193
236
|
}
|
|
194
237
|
|
|
195
|
-
|
|
196
|
-
|
|
238
|
+
private _loadStoredTabs() {
|
|
239
|
+
if (!this.storeKey || !this._store) return;
|
|
240
|
+
|
|
241
|
+
const storedData = this._store.get(this.storeKey);
|
|
242
|
+
const activeUri = this._store.get(this.storeKey + ':active');
|
|
243
|
+
if (storedData) {
|
|
244
|
+
try {
|
|
245
|
+
const tabs = JSON.parse(storedData) as StoredTab[];
|
|
246
|
+
if (Array.isArray(tabs)) {
|
|
247
|
+
tabs.forEach(tab => {
|
|
248
|
+
if (tab.uri && tab.title) {
|
|
249
|
+
const li = document.createElement('li');
|
|
250
|
+
li.setAttribute('tab-uri', tab.uri);
|
|
251
|
+
li.innerText = tab.title;
|
|
252
|
+
// Pass false to avoid re-saving what was just read
|
|
253
|
+
this.addItem(li, false);
|
|
254
|
+
|
|
255
|
+
if (activeUri && tab.uri === activeUri) {
|
|
256
|
+
setTimeout(() => {
|
|
257
|
+
li.click();
|
|
258
|
+
}, 100);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
} catch (e) {
|
|
264
|
+
console.warn('ZnNavbar: Failed to load stored tabs', e);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private _saveTabToStorage(newTab: StoredTab) {
|
|
270
|
+
if (!this.storeKey || !this._store) return;
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const storedData = this._store.get(this.storeKey);
|
|
274
|
+
let tabs: StoredTab[] = [];
|
|
275
|
+
if (storedData) {
|
|
276
|
+
tabs = JSON.parse(storedData) as StoredTab[];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Ensure we don't save duplicates
|
|
280
|
+
if (!tabs.some(t => t.uri === newTab.uri)) {
|
|
281
|
+
tabs.push(newTab);
|
|
282
|
+
this._store.set(this.storeKey, JSON.stringify(tabs));
|
|
283
|
+
}
|
|
284
|
+
} catch (e) {
|
|
285
|
+
console.warn('ZnNavbar: Failed to save tab', e);
|
|
286
|
+
}
|
|
197
287
|
}
|
|
198
288
|
|
|
199
289
|
private handleClick = (e: MouseEvent) => {
|
|
@@ -273,10 +363,12 @@ export default class ZnNavbar extends ZincElement {
|
|
|
273
363
|
${this._postItems}
|
|
274
364
|
${this._appended}
|
|
275
365
|
</ul>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
366
|
+
${this._expanding?.length > 0 ? html`
|
|
367
|
+
<div class="expandables">
|
|
368
|
+
${this._expanding}
|
|
369
|
+
<slot name="expand"></slot>
|
|
370
|
+
</div>
|
|
371
|
+
` : ''}
|
|
280
372
|
</div>`;
|
|
281
373
|
}
|
|
282
374
|
}
|
|
@@ -25,6 +25,11 @@ ul.navbar {
|
|
|
25
25
|
padding-top: 0;
|
|
26
26
|
font-size: var(--zn-font-size-medium);
|
|
27
27
|
white-space: nowrap;
|
|
28
|
+
|
|
29
|
+
a {
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
color: inherit;
|
|
32
|
+
}
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -146,7 +151,7 @@ ul.navbar {
|
|
|
146
151
|
|
|
147
152
|
}
|
|
148
153
|
|
|
149
|
-
.navbar__container--stacked {
|
|
154
|
+
.navbar__container--stacked.navbar__container--icon-bar {
|
|
150
155
|
display: inline;
|
|
151
156
|
}
|
|
152
157
|
|